REST聊天应用升级——妖怪哲开始打通后端6

REST聊天应用升级——妖哲开始打通后端6

Hello,我又回来了,这周差不多完成了聊天系统的终极升级版本。(不告诉你是啥,等我更新完就知道是啥啦(我是程序员你打我啊

遗留问题修补

关于上个版本的REST API聊天记录还有一些要改进的地方,具体细节看下面
点我我是传送门

实时消息

还记得聊天(群聊版)的最重要的功能是啥吗,是实时消息。而之前的聊天程序在设计的时候有一个缺陷。

getMessage(获取聊天记录)和UpdateMessage(渲染聊天语句)总是在发送完消息之后调用,也许你会说这并没有什么错.但仔细想一下,如果在你按下发送按钮之前,你的老板在群里发了一条让你去见她,然后你过了好久才发送一条消息.发完后看见原来老板一两个小时前就在等(然后你就悲剧了).所以作为一个群聊软件即时获取消息是很重要的。
当然如果没有即时这个属性,作为一个聊天版还是绰绰有余的。

所以我们要把之前的设计思路改成下面这个
REST聊天应用升级——妖怪哲开始打通后端6

将getMessage()作为实时调用函数之后其实就可以废弃之前click()事件中的getMessage函数了,但是如果为了避免延迟(虽然没什么用)你也可以继续保留这段代码。
代码可以从GitHub上获取,欢迎Fork本项目。

接下来我们就来修正一下之前的代码。
如上图所示,最主要的地方在于getMessage()的调用,所以打开之前的app_1.js,之前的结构是这样的

var ParseApplicationID = "...";
var ParseRESTKey       = "...";
//确保DOM载入完成
$(document).ready(function(){
    getMessage();//需要修改的地方
    $("#send").click(function(){...});
})
//获取消息
function getMessage(){...}
//绘制消息
function updateView(){...}

可以看到,我们之前只是在打开Web应用的一瞬间获取过一次消息列表,之后都要被动的等待点击事件。所以我们改成这样

var ParseApplicationID = "...";
var ParseRESTKey       = "...";
//确保DOM载入完成
$(document).ready(function(){
    setInterval(function(){getMessage();console.log('get!');},2000);
    $("#send").click(function(){...});
})
//获取消息
function getMessage(){...}
//绘制消息
function updateView(){...}

看上去并没有多大变化

只是用setInterval()1定时函数将getMessage封装了起来。
以2000**毫秒**为单位不断调用getMessage(当然还有一个提示用的log)
保存一下我们的项目,用浏览器运行一下,你应该在控制台看见这样的输出
REST聊天应用升级——妖怪哲开始打通后端6
浏览器在不断从Parse云端获取消息列表时刻更新至本地页面!
这样我们就不会因为没有得到即时消息被老板炒鱿鱼啦!

这边还是会有一些问题,我们get到的信息会一直与之前的消息重合,而这些XHR形式的信息2资源会占用内存,所以更加明智的方案应该加入xhr销毁机制,或者有选择地从云端获取消息——此处我并没有修改。

仅仅有这些还是不够的(如果你一不小心发错了消息(你懂得)在这个聊天系统中没办法撤回!依旧会被老板炒鱿鱼啊!
所以我们来搞一个消息撤回系统

消息撤回

恩,其实消息撤回吗,和之前的发送消息几乎没什么不一样。我们来看一下下面这张图
REST聊天应用升级——妖怪哲开始打通后端6
没错就是获取一个点击事件之后执行一个函数,很明显这个函数应该是和之前的post方法相反的,这里就要引入http的另一种请求delete。先不要管他,我们先来思考一下这个点击事件该做些什么。
send的click事件中,将input中的内容打包成json发送,而删除好像并不需要什么输入。
那真是大错特错,删除也是需要输入的。为什么?道理很简单,我们要做的事情是在Parse的一个叫做MessageBoard的集合中找到一条消息并且删除,那么找到消息就是最初的目标,为了找到消息,我们必须要有一个索引,这可以是已有的字段或者默认排序。

我们打开Parse后台看看已有字段
REST聊天应用升级——妖怪哲开始打通后端6
wow,惊讶的发现除了我们自己创建的username 和message字段之外,还自动提供了createTime,updateTime以及objectId三个字段(这些是ajax方法自己生成的)。
这样思路就很清晰了,我们完全可以拿这个独一无二的objectId来搜索。所以,接下来的事情你应该很清楚了,

  • 创建一个id为delete的撤回按钮和一个用来输入objectId的输入框。(记得使用placeholder做提示)
  • 此处参照之前的教程应该会很简单就不贴出html代码了

  • 输出一列objectId
  • 修改updateView函数,因为obectId已经包含在响应值中,所以直接引用即可

    function updateView(message){
        var table=$('.table tbody');//使用选择器选中元素并且创建一个引用
        table.html('');//清空这个元素的inner HTML
        //使用jQuery.each便利消息
        $.each(message.results,function (index,value){
            var trEl = 
            $('<tr><td>'
                + value.username
                + '</td><td>'
                + value.message
                + '</td><td>'
                + value.objectId
                + '</td></tr>');
            //追加表格
            table.append(trEl);
        });
        console.log(message);
    }

    delete

    还记得之前说的http的delete请求吗?现在就要学习这个屌东西了。
    关于详细的HTTP请求请点击传送门HTTP请求方法,ajax()请求
    回忆一下之前的.ajax()post请求
    REST聊天应用升级——妖怪哲开始打通后端6
    我们撤回/删除消息的代码结构也跟他差不多

    //使用选择器获取撤回按钮
    $("#delete").click(function(){
            var objectid  = $('input[name=objectId]').val();//获取输入的objectId
            console.log('Delete!');
            console.log(objectid);
            $.ajax({
                url : 'https://api.parse.com/1/classes/MessageBoard/'+objectid,//注意url这边的变化
                headers : {
                    'X-Parse-Application-Id' : ParseApplicationID,
                    'X-Parse-REST-API-Key'   : ParseRESTKey
    
                },
                contentType : 'application/json',
                dataType    : 'json',
                data        : JSON.stringify({
    
                }),
                type        : 'DELETE',
                success     : function(){
                    getMessage();
                },
                error       : function(){
                    console.log('error');
                }
            });
        });

    最大的区别在于

    0.方式是DELETE
    1.data信息是空的(因为我们是为了删除)
    2.objectId直接附着在messageBoard的url之后(这样直接对集合中的对象进行删除操作)

    好了,运行一下(为了体验即时性,我建议你开两个(
    是不是删除操作以及发送消息都流畅无误呢。

    于是,你终于又找到了缺陷(对的(无限的聊天记录,让整个页面变得过长。没错我们现在就来搞一个卷动

    scroll

    屏幕卷动这个功能最主要使用css加js实现
    首先,我们使用css 的overflow属性,在html中穿件一个div类将聊天面板包裹起来,并且id标记为ChatPanel。然后创建一个css文件

    #ChatPanel{height:600px; overflow-y:auto;}

    使得之前的Div块固定高度为600,超过这个长度的内容会自动卷动。
    这样还没完(因为你尽可以引入css运行一下(聊天还要手动拖动才能(还是非常的不方便)
    我们最后要做的事情就是让消息自动卷动到底部。
    使用以下的js代码

    function scrollBottom(){
        var div = document.getElementById('ChatPanel');
        div.scrollTop = div.scrollHeight; 
    } 

    获取chatpanel,并且使他卷动到尽头,关于各种Height之间的关系不妨参考这篇文章:传送
    考虑一下应该在哪里执行这个?

    事实上滚动到最底部往往发生在发送完消息之后,所以上次的设计模式正好可以给这个滚动来做,由于代码很少,所以直接插入updateView底部即可。这样我们的聊天软件就大功告成了。
    打开试一下
    REST聊天应用升级——妖怪哲开始打通后端6

    当然这样还是有一点不方便,就是在浏览聊天记录的时候有新消息来就会一直向下滚动。可以根据div的doc高度有没有变化来进行判定。


    1. 能够实现定时调用的除了setInterval之外还有setTimeout,他们之间的区别请参考这里 ↩
    2. 关于XMLHTTPRequest ↩