代码改变世界

做一个群组聊天页面

2014-06-11 20:39  轩脉刃  阅读(2495)  评论(2编辑  收藏  举报

要做个群组聊天的页面,参考微信的web版本,大致就是分为左右两列,左边是群组列表,右边是群组中的对话

示例图如下:

 

这个页面风格是使用ACE做的,再次啧啧下,ACE真TMD强大,这个页面的风格很招人喜欢。

 

做这个页面刚开始的时候我走了弯路,初步想的是使用iframe,左侧群组聊天页面是页面加载的,右侧的群组对话框是个iframe。然后点击左侧的任意一个群组,右侧的对话iframe就修改src,然后更新对话的时候也超简单,直接iframe重新加载一下就ok了。

但是呢,后来发现,我这样需要写的controller反而更多,一个iframe的controller,一个页面本身的controller,然后在两个iframe需要传递一些东西,特别是群组id。最大的困难就是更新,当我在iframe中发了一条消息之后,iframe中的条目能很快更新,但是外面的页面(由于是使用轮询)就没办法及时更新了。

后来总结了下,我整个页面就使用最统一的方式,html+jsonp的形式,使用一个页面controller,然后每个行为触发一个jsonp,整体做下来,结果就是js量极速增大。但是,不算坏事。

 

页面逻辑是这样:

首先页面初始加载群组列表

其次点击群组名称,同步加载出现右侧的对话框。注意这里是使用同步加载。因为从用户体验上,如果使用异步,点击了群组却没有出现对话框,会有bug的感觉。jquery的ajax是有提供jsonp和同步调用的:

代码:

$("[name=talk_talk]").click(function(event){
    event.preventDefault();

    var target = event.target;
    var mgid = $(target).attr("data-mgid");
    var action = "http://api.test/group/messageList"
    var params = "mgid=" + mgid;

    $.ajax({
        type: "get",
        dataType: "jsonp",
        async:false,
        url: action,
        data: params,
        jsonp: 'callback',
        jsonpCallback: 'callback231',
        success: function(data) {
            if (data.msg == 'ok') {
                var messages = data.messages;
                var users = data.users;
                var message_contents = '';
                for(var i=0; i< messages.length; i++) {
                    var message = messages[i];
                    var sid = message.sid;
                    var sender = users[sid];
                    message.sender = sender;
                    message_content = getDialogHTML(message);
                    message_contents = message_contents + message_content;
                }    
                $("#messages_show").html(message_contents);
                $("#messages_show").attr("cur_mgid", mgid);
                $("#group_unreadflag_" + mgid).hide();
                $("#widget-box-dialog").show();
            }
        }
    });
});

这里的ajax的dataType设置为jsonp表示是个jsonp请求,加上后面的jsonp和jsonpCallback,表示调用的时候我传递的请求带上了callback=callback231。

这里的jsonpCallback也是可以不写的,但是如果不写jquery会使用形如:callback_321342_324123这样的函数名来替换。但是我希望服务器端使用白名单机制来控制callback只能是字母和数字(Yii):

if (!empty($callback) && ctype_alnum($callback)) {
    echo "{$callback}(" . CJSON::encode($ret) . ")";
    Yii::app()->end();
}

所以我就手动设置了callback函数。相关的安全考虑我记得以前有一篇文章写过:http://www.cnblogs.com/yjf512/p/3222269.html

ajax的默认是异步的,所以要设置同步的话需要设置async:false。

 

接着就是轮询函数

服务端有个jsonp接口能根据我返回的最新时间,返回这个时间后我收到的所有群组消息。

代码几乎同上,不同的就是这个行为应该且必须是异步的。然后做两个事情:一件事情是如果左侧的群组有新消息,设置一个标志表示有新消息。另一个事情是如果右侧的对话显示的是当前这个群组的对话,就增加一个最新的消息放到上面。

 

然后是发送消息,基本同上。

好吧,主要还是秀一下ACE模板,看的爽。