要做個群組聊天的頁面,參考微信的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模板,看的爽。
