使用JS將聊天記錄聚合在一起
前言
我們在QQ上聊天時,同一分鐘的聊天記錄會被放在一起展示,當我們發送消息時,每條消息的發送時間都會精確到秒,那么他是如何實現將這些數據按分鐘劃分到一起的顯示的呢?
今天在給我開源項目的聊天記錄添加消息發送時間展示時,正好遇到了這個問題,一開始想不明白應該如何處理這些數據,后來經過一番思考后,終于有了實現思路,將其實現了,本文就跟大家分享下我的實現思路以及過程,歡迎各位感興趣的開發者閱讀本文。
實現思路
先跟大家看下我的數據,如下所示:
- [{
- "createTime": "2020-12-21 20:58:19",
- "avatarSrc": "https://www.kaisir.cn/uploads/1ece3749801d4d45933ba8b31403c685touxiang.jpeg",
- "msgId": "121710f399b84322bdecc238199d6888",
- "msgText": "/壞笑/",
- "userName": "神奇的程序員",
- "userId": "c04618bab36146e3a9d3b411e7f9eb8f",
- "status": false
- }, {
- "createTime": "2020-12-21 20:58:22",
- "avatarSrc": "https://www.kaisir.cn/uploads/1ece3749801d4d45933ba8b31403c685touxiang.jpeg",
- "msgId": "121710f399b84322bdecc238199d6888",
- "msgText": "還有人嗎",
- "userName": "神奇的程序員",
- "userId": "c04618bab36146e3a9d3b411e7f9eb8f",
- "status": false
- }, {
- "createTime": "2020-12-21 20:58:46",
- "avatarSrc": "https://www.kaisir.cn/uploads/1ece3749801d4d45933ba8b31403c685touxiang.jpeg",
- "msgId": "121710f399b84322bdecc238199d6888",
- "msgText": "聊天記錄,添加了消息發送時間",
- "userName": "神奇的程序員",
- "userId": "c04618bab36146e3a9d3b411e7f9eb8f",
- "status": false
- }, {
- "createTime": "2020-12-21 20:58:52",
- "avatarSrc": "https://www.kaisir.cn/uploads/1ece3749801d4d45933ba8b31403c685touxiang.jpeg",
- "msgId": "121710f399b84322bdecc238199d6888",
- "msgText": "現在看起來就方便多了",
- "userName": "神奇的程序員",
- "userId": "c04618bab36146e3a9d3b411e7f9eb8f",
- "status": false
- }, {
- "createTime": "2020-12-21 21:35:27",
- "avatarSrc": "https://www.kaisir.cn/uploads/1ece3749801d4d45933ba8b31403c685touxiang.jpeg",
- "msgId": "121710f399b84322bdecc238199d6888",
- "msgText": "/壞笑/",
- "userName": "神奇的程序員",
- "userId": "c04618bab36146e3a9d3b411e7f9eb8f",
- "status": false
- }]
觀察上方數據,我們發現:每個消息對象都有一個createTime屬性,它是消息的發送時間,精確到了時分秒,現在我們要做的就是把同一分鐘的時間只保留一個createTime屬性,渲染時間的時候只渲染擁有createTime屬性的對象,這樣就做到了將相同分鐘的數據渲染到了一起。
大體思路就是這樣,接下來我們看下具體的思路:
- 聲明一個對象命名為timeObj,存放消息對象里createTime字段的年-月-日 時:分,聲明一個新的消息記錄數組finalTextList存放處理好的數據
- 遍歷消息記錄數組,獲取當前遍歷到的消息記錄對象
- 獲取遍歷到的消息記錄對象的createTime屬性,截取 年-月-日 時:分,聲明一個變量time來保存
- 判斷time是否存在于timeObj中
- 如果存在就刪除遍歷到的消息記錄對象中的createTime屬性,將刪除屬性后的消息記錄對象放進finalTextList中
- 否則將time作為屬性放進timeObj中,將遍歷到的消息記錄對象原封不動的放進finalTextList中
處理好數據后,我們在渲染時判斷當前渲染項里是否存在createTime,如果存在就渲染。
實現過程
接下來,我們在拿到接口返回的數據后將其按照上述思路進行處理。
處理接口返回的數據
如下所示res.data.messageTextList為接口返回的消息記錄列表。
- // 消息內容列表
- const messageTextList: Array<msgListType> = res.data.messageTextList;
- // 處理好的消息內容數組
- const finalTextList: Array<msgListType> = [];
- // 時間存放對象
- const timeObj: { [key: string]: boolean } = {};
- // 處理消息內容列表,同一分鐘的數據只保留一個創建時間
- for (let i = 0; i < messageTextList.length; i++) {
- // 消息對象
- const messageObj = messageTextList[i];
- // 獲取時間的 年-月-日 時:分
- const time = (messageObj.createTime as string).substring(0, 16);
- // timeObj中已經存在time,則移除當前消息對象的createTime
- if (_.has(timeObj, time)) {
- // 移除createTime屬性
- _.unset(messageObj, "createTime");
- // 將移除createTime屬性的消息對象放進處理好的消息數組中
- finalTextList.push(messageObj);
- } else {
- // 將time作為key放進timeObj中
- timeObj[time] = true;
- // 原封不動的將消息對象放進處理好的消息數組中
- finalTextList.push(messageObj);
- }
- }
- // 渲染消息列表
- this.renderPage(finalTextList, {});
上述代碼中的msgListType為消息記錄對象的類型定義,has為lodash的方法用于判斷對象中是否包含某個屬性,unset也為lodash的方法用于移除對象中的某個屬性。
處理推送數據
收到服務端推送的數據時,我們要將服務端推送的消息聚合到已經渲染的聊天記錄里,如果不是同一分鐘的消息則渲染新的時間,因此我們要取出當前推送消息的createTime字段,截取年-月-日 時:分判斷其是否在已渲染的消息記錄列表里,如果不存在則原封不動的渲染,否則就刪除createTime字段后渲染,代碼如下:
- // 接收到服務端推送的新消息,渲染單個消息對象
- const thisSenderMessageObj: msgListType = {
- msgText: msgObj.msgText,
- avatarSrc: msgObj.avatarSrc,
- userId: msgObj.userId,
- userName: msgObj.userName,
- createTime: msgObj?.createTime
- };
- // 找到消息記錄列表中與新消息的同一分鐘的消息,移除新消息的createTime對象
- for (let i = 0; i < this.senderMessageList.length; i++) {
- const messageObj: msgListType = this.senderMessageList[i];
- // 截取當前消息與新消息發送時間的 年-月-日 時:分,判斷其是否相等
- if (_.isEqual( messageObj.createTime?.substring(0,16),thisSenderMessageObj.createTime?.substring(0, 16))) {
- // 移除新消息的createTime屬性
- _.unset(thisSenderMessageObj, "createTime");
- }
- }
- // 解析并渲染
- this.messageParsing(thisSenderMessageObj);
msgObj為服務端推送的消息
渲染頁面
接下來我們看看頁面的渲染代碼,如下所示,只渲染對象中包含createTime屬性的數據
- <!--消息發送時間-->
- <div class="snder-time-panel" v-if="item.createTime">
- <span>{{ item.createTime.substring(5, 16) }}</span>
- </div>
實現效果
最后我們來看看實現的效果,如下所示:
我們再來發送一條消息看看效果,如下所示:圖片太大此處無法顯示,請在尾部閱讀原文進行查看。
項目地址
代碼地址:message-display.vue
在線體驗地址:chat-system
本文轉載自微信公眾號「 神奇的程序員k」,作者 神奇的程序員k 。轉載本文請聯系 神奇的程序員k公眾號。