要做个群组聊天的页面,参考微信的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模板,看的爽。