1、前言 前端
2、主要內容 vue
一、分析實現的邏輯ios
第一步:用戶登陸成功以後須要找到目的對象發起私聊。vuex
第二步:數據雙向綁定監聽輸入內容express
第三步:點擊發送按鈕的時候請求後端接口。json
第四步:後端創建接口完畢後返回前端聊天數據axios
第五步:前端觸發後端定義的socket.io中接收消息的邏輯後端
第六步:接收到後臺回覆的數據,而後進行數據渲染。api
二、分步驟實現數組
2.1用戶登陸成功以後爲每一個用戶分配一個socket.io
(1)登陸成功以後觸發後臺的
asyn Login(){ ... .... ....省略 //登陸成功後跳轉到我的中心界面,觸發後臺定義的方法爲每個登陸成功的用戶分配一個socketid socket.emit('login', user.username); }
(2)後臺新建一個sechma專門用戶存放每一個用戶的socketid
let express = require('express'); let mongoose = require('mongoose'); module.exports = new mongoose.Schema({ socketid:String, username:String });
(3)調用封裝的保存用戶socketid方法
//=====================封裝 let Idtoid = require('../Models/Idtoid') module.exports = class socketHandler{ static async savaUserSocketId(username, socketId){ //保存用戶的id和socketid await Idtoid.findOne({ username: username }).then((rs)=>{ if(!rs){ new Idtoid({ username: username, socketid: socketId }).save().then(()=>{ }) }else { Idtoid.update({ username: username }, { socketid: socketId }).then(()=>{ }) } }) } } //=========================調用 socket.on('login', (username)=>{ console.log('有用戶登陸') socketHandler.savaUserSocketId(username, socketId) })
2.2數據雙向綁定觸發消息發送的方法
(1)前端data中定義content實現數據雙向綁定,(這裏須要再調用請求用戶信息的方法,請求到當前聊天的用戶信息)
data(){ return{ chatId: this.$route.query.chatId, chatName: this.$route.query.chatName, content:'',//發送的對話內容 chatUserInfo:{}, //請求到的聊天的用戶信息 chatdataList:[] //當前聊天的信息,本身發的信息存到一個數組中 } },
(2)數據雙向綁定完成觸發發送
//發送消息 sendContent(){ //1.先判斷當前用戶是否登陸 if(!this.userInfo._id){ Toast("請先登陸!") return; } //2.校驗輸入的內容是否爲空 if(this.content==""){ return } //3.請求後端接口 this.$axios.post('/api/chat/chatwith', { chatWithId: this.chatUserInfo._id,//聊天對象 user_id: this.userInfo._id,//當前登陸的用戶 content:this.content }).then((res)=>{ console.log(res) this.chatdataList.push({//保存發送到的和接收到的消息 user_id:{ avater: this.userInfo.avater }, chatWith:{ _id: this.chatId }, addTime: Date.now(), content: this.content }) //將當前的發送的信息同步更新到vuex中 this.UPDATE_CHATLIST({ _id: this.chatUserInfo._id, from_user: this.chatName, message: this.content, time: Date.now(), me:true,//判別是否是本身發送 avater:this.chatUserInfo.avater }) console.log(this.chatUserInfo._id) console.log(this.chatName) console.log(this.content) console.log(Date.now()) console.log(this.chatUserInfo._id) //發給對方的數據 let data = { from_user: this.userInfo.username, to_user: this.chatName, message: this.content, time: Date.now(), avater: this.userInfo.avater, _id: this.userInfo._id } socket.emit('chat', data) this.content='' }) },
(3)後端實現邏輯
思路:發送消息過來的時候先判斷是否兩個聊天用戶之間已經創建好了聯繫,若是已經創建好了聯繫只須要更新聊天數據,若是尚未創建好聯繫先創建聯繫。
router.post('/chatwith', (req, res) => { let chatWith = req.body.chatWithId; //獲取到前端傳來的聊天用戶 let user_id = req.body.user_id; //獲取到當前登陸的用戶 let content = req.body.content; //獲取到輸入的聊天內容 //新建一個聊天內容對象 new ChatContent({ chatWith: chatWith, //聊天用戶 user_id: user_id, content: content }).save().then((newContent) => { //查找兩個用戶之間是否已經創建好了聯繫 ChatRelation.findOne({ $or:[{ userA:user_id, userB:chatWith },{ userB:user_id, userA:chatWith }] }).then((rs)=>{ //若是已經創建好了聯繫,只須要更新聊天數組 if (rs){ let chatContent = rs.chatContent; chatContent.unshift(newContent._id); ChatRelation.update({ _id:rs.id },{ chatContent:chatContent }).then(()=>{ res.json({ code:0, data:newContent }) }) }else { //沒有創建好聯繫就新創建聯繫 new ChatRelation({ userA:user_id, userB:chatWith, chatContent:[newContent._id] }).save().then(()=>{ res.json({ code:0, data:newContent }) }) } }) }) });
這裏涉及到的兩個sechma對象:
chatContent.js:
let express = require('express') let mongoose = require('mongoose') module.exports = new mongoose.Schema({ user_id:{//當前的用戶id type:mongoose.Schema.Types.ObjectId, ref:'User' }, chatWith:{//私信的用戶 type:mongoose.Schema.Types.ObjectId, ref:'User' }, addTime:{//發送內容的時間 type:Date, default: Date.now }, content:{ type: String }, unread:{//是否默認未讀 type: Boolean, default: true } })
chatRelation.js
let express = require('express'); let mongoose = require('mongoose'); module.exports = new mongoose.Schema({ userA:{ type:mongoose.Schema.Types.ObjectId, ref:'User' }, userB:{ type:mongoose.Schema.Types.ObjectId, ref:'User' }, chatContent:[{ type:mongoose.Schema.Types.ObjectId, ref:'ChatMessage' }], });
(4)消息回覆後端邏輯實現
/* 封裝socket.io,是爲了獲取server以便監聽 */ let Idtoid = require('../Models/Idtoid') let socketHandler = require('./socketioHander.js'); //socket要實現的具體邏 var socketio = {} var socket_io = require('socket.io') //獲取io socketio.getSocketio = function(server){ var io = socket_io.listen(server) io.sockets.on('connection', socket=>{ console.log('鏈接成功') const socketId = socket.id socket.on('login', (username)=>{ console.log('有用戶登陸') socketHandler.savaUserSocketId(username, socketId) }) socket.on('chat', (data)=>{ console.log('有用戶發起聊天啦') console.log(data) Idtoid.findOne({ username: data.to_user// }).then((rs)=>{ //給對應的人發消息 io.to(rs.socketid).emit('receiveMsg', { from_user: data.from_user, message: data.message, time: data.time, avater:data.avater, _id:data._id }) }) }) }) } module.exports = socketio
(5)前端觸發監聽後端回覆邏輯
//接收對方發來的數據 updateBySocket(){ socket.on('receiveMsg', (data)=>{ //判斷是否是當前的對話框 console.log(111111) if(data.from_user == this.chatName){ //把接收到的消息保存到聊天記錄中, this.chatdataList.push({ chatWith:{ _id: this.userInfo._id }, user_id:{ avater: data.avater }, addTime: data.addTime, content: data.message }) this.UPDATE_CHATLIST({ _id: this.chatUserInfo._id, from_user: this.chatName, message: data.message, time: data.addTime, me: true, avater: this.chatUserInfo.avater }) } }) },
(6)vuex中的this.UPDATE_CHATLIST方法記錄着當前的每個聊天關係,以及最新消息
//私聊部分,獲取到聊天對象的方法 [UPDATE_CHATLIST](state, data){ let flag = 0;//判斷新的聊天是否存在於當前的列表中 state.chatList.forEach((item)=>{ if (item.chatWith.username == data.from_user) { flag = 1; if (!data.me) {//判斷當前是否在對話框頁面中 item.unread++; state.unread++; } //更新 item.content = data.message; item.addTime = data.time; //按添加時間排序 state.chatList.sort((a, b) => { return new Date(b.addTime) - new Date(a.addTime) }); //跳出循環 return false; } }); //是新的而且不在對話框頁面 if (!flag&&!data.me) { //添加到第一條 state.chatList.unshift({ chatWith: { avater: data.avater, username: data.from_user, _id: data._id }, addTime: data.time, content: data.message, unread: 1 }); state.unread++; }else if (!flag&&data.me){//新的而且在對話框頁面,不須要增長unread state.chatList.unshift({ chatWith: { avater: data.avater, username: data.from_user, _id: data._id }, addTime: data.time, content: data.message, }); } },