This article example shares the specific code of Vue to implement web online chat for your reference. The specific content is as follows The final effectImplementation processThe implementation of infinite scrolling form has been introduced before, so I will not repeat it here. If you are not clear about it, you can check it through the portal in the previous document. Main features of real-time online chat
Without further ado, let's get straight to the code Backend return data formatI think all designs and functional implementations are based on data, so let's first take a look at the data format returned by the backend: { "code": 200, // Response code "msg": "OK", // Response message "total": 1, "sysTime": "2020-12-16 15:23:27", // System response time "data": [{ "avatar": "", // User avatar "content": "{\"type\":\"txt\",\"msg\":\"Hello! \"}", // message content"isRead": 0, // has it been read? "isOneself": 0, // is it a message sent by yourself? 0 for no, 1 for yes"msgId": 10, // message ID, used for deduplication"nickName": "碧海燕鱼", // user nickname"userCode": "202012162030202232" // user code}] } It should be noted here that the content field returns a string data in JSON format, and the content format is as follows: // Text message { "type": "txt", "msg":"Hello" //Message content} // Picture message { "type": "img", "url": "Image address", "ext":"jpg", "width":360, //width"height":480, //height"size": 388245 } // Video message { "type": 'video', "url": "http://nimtest.nos.netease.com/cbc500e8-e19c-4b0f-834b-c32d4dc1075e", "ext":"mp4", "width":360, //width"height":480, //height"size": 388245 } // Location message { "type": "local", "address":"No. 599, Wangshang Road, Hangzhou, Zhejiang, China", //Geographic location "longitude":120.1908686708565, // Longitude "latitude":30.18704515647036 // Latitude} HTML Code <template> <Modal title="Online communication" v-model="chatVisible" draggable footer-hide :width="580" @on-cancel="cancel"> <div class="chat"> <div class="chat-message-body" id ="chatform" @scroll="scroll" > <Spin v-if="loading"> <Icon type="ios-loading" size=18 class="spin-icon-load"></Icon> </Spin> <div dis-hover v-for="(item,index) in data" :key="index" class="message-card"> <div :class="item.isOneself == 1?'message-row-right':'message-row-left'"> <img :src="item.avatar?item.avatar:defualtAvatar" height="35" width="35" > <div class="message-content"> <div :style="item.isOneself == 1?'text-align:right;display: flex;flex-direction:row-reverse':''"> {{item.nickName}} <span class="message-time"> {{item.createTime}}</span> </div> <div class="message-body"> {{item.content.msg}} </div> </div> </div> </div> </div> <Input v-model="form.msg" type="textarea" style="margin:10px 0;" placeholder="Be more proactive, the world will be bigger!" :rows="4" /> </div> <div class="footer-btn"> <Button @click="cancel" type="text">Cancel</Button> <Button type="primary" @click="sendMsg">Send</Button> </div> </Modal> </template> Note: The display styles of messages sent by yourself and others are different, so you need to use the isOneself field to distinguish the display styles. JavaScript code <script> import {listMsg,sendMsg } from "@/api/index"; export default { name: "chat", props: { value: { type: Boolean, default: false } }, data() { return { chatVisible:this.value, loading:false, defualtAvatar:require('../../assets/defult-avatar.svg'), // The backend does not return the default avatar. Note: require request method is required to dynamically access local files data:[], distincData:[], // message deduplication array offsetMax:0, // maximum offset, record the current maximum ID, and only get data larger than this ID each time when polling data at a scheduled time in the future offsetMin:0, // minimum offset, record the current minimum ID, and only get data larger than this ID each time when sliding up searchForm:{ // form data submitted each time data is obtained or loaded for the first time pageNumber: 1, pageSize: 20 }, form:{ // Send data to submit data form content:"", msg:"" }, timerSwitch:0 // Timer switch, closed by default}; }, methods: { init(){ }, loadMsg(){ // The form opens and loads a page of data by default. The form runs once in a certain period. let that = this; this.searchForm.offsetMax = this.offsetMax; listMsg(this.searchForm).then(res=>{ if (res.code == 200) { res.data.forEach(e => { // Mark the maximum offset if (that.offsetMax < e.msgId) { that.offsetMax = e.msgId; } e.content = JSON.parse(e.content); that.data.unshift(e) that.distincData.push(e.msgId); // Mark the maximum offset. The data returned by the backend is in reverse order, so the last ID is the latest that.offsetMin = e.msgId; }); // After data loading is complete, the scroll bar scrolls to the bottom of the form this.scrollToBottom(); } }); }, show(){ //Open the form and initialize the data //Initialize the data this.data = []; this.distincData = []; this.offsetMax = 0; this.offsetMin = 0; this.searchForm.pageNumber = 1; this.searchForm.pageSize = 20; this.form = { content:"", msg:"" }; this.loadMsg(); this.chatVisible = true; // Turn on the timer this.timerSwitch = 1; this.reloadData(); }, sendMsg(){ // Send message if(!this.form.msg){ this.$Message.warning("Cannot send blank message"); return; } let content = { // Encapsulate message body type:"txt", msg:this.form.msg }; this.form.content = JSON.stringify(content); sendOrderMsg(this.form).then(res=>{ if (res.code == 200) { res.data.content = JSON.parse(res.data.content); this.data.push(res.data) this.form.msg=""; this.distincData.push(res.data.msgId); this.scrollToBottom(); // Sending a message only returns the current one. The other party may have already sent the message, so the offset will not be modified.} }); }, scrollToBottom(){ //Scroll to the bottom of the form this.$nextTick(()=>{ let chatform = document.getElementById("chatform"); chatform.scrollTop = chatform.scrollHeight; }); }, // Scroll to the top and retrieve historical data according to the paging parameters. No need to modify the offset mark, but need to judge the re-scroll(){ let chatform = document.getElementById("chatform"); let scrollTop = chatform.scrollTop; if(scrollTop == 0){ this.loading =true; let that = this; this.searchForm.offsetMin = this.offsetMin; this.searchForm.offsetMax = ""; listMsgByOrder(this.searchForm).then(res=>{ this.loading =false; if (res.code == 200) { res.data.forEach(e => { if (that.distincData.indexOf(e.msgId) < 0) { e.content = JSON.parse(e.content); that.data.unshift(e); that.distincData.push(e.msgId); // Modify the minimum offset if (that.offsetMin > e.msgId) { that.offsetMin = e.msgId; } } }); } }); } }, reloadData(){ // Determine whether the timer switch is on. If it is on, execute the timer if(this.timerSwitch){ setTimeout(() => { let params = {}; params.pageNumber = 1; params.pageSize = 20; params.offsetMax = this.offsetMax; let that = this; listMsgByOrder(params).then(res=>{ if (res.code == 200) { res.data.forEach(e => { // Modify the maximum offset and put it before the duplicate check to prevent the current message from being put into the message list but the offset value is not there if (that.offsetMax < e.msgId) { that.offsetMax = e.msgId; } if (that.distincData.indexOf(e.msgId) < 0) { e.content = JSON.parse(e.content); that.data.push(e) that.distincData.push(e.msgId); // Receive a new message, determine the height, if the current scroll bar height is less than 100 from the bottom, slide to the bottom let chatform = document.getElementById("chatform"); let gap = chatform.scrollHeight -chatform.scrollTop; if(gap >0 && gap < 400){ this.scrollToBottom(); } } }); that.reloadData(); } }); },1000*2); } }, cancel(){ // To close the form, you need to turn off the prompt task switch as well. this.chatVisible = false; this.timerSwitch = 0; } }, mounted() { } }; </script> CSS Code <style lang="less"> .message { height: 350px; } .ivu-card-body { padding:5px; } .ivu-modal-body{ padding: 0px 16px 16px 16px; } .chat-message-body { background-color:#F8F8F6; width:545px; height: 350px; overflow:auto; } .message-card { margin:5px; } .message-row-left { display: flex; flex-direction:row; } .message-row-right { display: flex; flex-direction:row-reverse; } .message-content { margin:-5px 5px 5px 5px; display: flex; flex-direction:column; } .message-body { border:1px solid #D9DAD9; padding:5px; border-radius:3px; background-color:#FFF; } .message-time { margin:0 5px; font-size:5px; color:#D9DAD9; } .footer-btn { float:right; margin-bottom: 5px; } .spin-icon-load { animation:ani-spin 1s linear infinite; } @keyframes ani-spin{ form{transform:rotate(0deg);} 50% {transform: rotate(180deg);} to {transform: rotate(360deg);} } </style> The above is the full content of this article. I hope it will be helpful for everyone’s study. I also hope that everyone will support 123WORDPRESS.COM. You may also be interested in:
|
<<: Implementation of TCPWrappers access control in Centos
>>: Will MySQL execute the update statement again if it has the same data as the original one?
Using win docker-desktop, I want to connect to co...
Docker queries or obtains images in a private reg...
1. In the control panel, uninstall all components...
The database I use is MySQL database version 5.7 ...
Install Docker You have to install Docker, no fur...
This is a cheating scheme for voting websites wit...
I believe everyone knows HTML and CSS, knows the ...
Baidu Cloud Disk: Link: https://pan.baidu.com/s/1...
Recently, the company purchased a DELL R730 serve...
The previous articles were all my own learning lo...
The MySQL development team officially released th...
Table of contents 1. Operation of js integer 2. R...
No matter you are installing Windows or Linux ope...
The function to be implemented today is the follo...
There are few and inadequate installation tutoria...