赞
踩
通过上一篇文章https://blog.csdn.net/beekim/article/details/134176752?spm=1001.2014.3001.5501,
我们已经在vue-advanced-chat中替换掉原有的firebase,用socket.io简单的实现了聊天功能。
现在需要自义定该组件,改造成我们想要的样子:
先将比较重要的几块提取出来
ws的几个事件是参考firebase的封装方式
socket.ts
import { reactive } from 'vue'; import { io, Socket } from 'socket.io-client'; console.log(import.meta.env.VITE_GLOB_CHATROBAT_URL); //这个地址我配置在.env配置文件里面的,方便维护 const wsUrl:any = import.meta.env.VITE_GLOB_CHATROBAT_URL; class SocketService { socket: Socket; state: any; constructor() { this.state = reactive({ id: '',//这里面可以自义定变量 }); // http://192.168.1.50:8567/ // http://140.207.154.220:8567 // ws://localhost:3333 this.socket = io(wsUrl, { autoConnect: false, // 禁止自动连接 extraHeaders: { 'Access-Control-Allow-Origin': '*', // 设置跨域请求头 }, transports: ['websocket', 'polling', 'flashsocket'],//注意点:加上这个配置ws才可以注册到后台 }); connect() { this.socket.connect(); console.log('socket connect'); } disconnect() { this.socket.disconnect(); console.log('socket disconnect'); } /** * @description 房间更新 * @param bn_user_name 当前登录人的邮箱 ,必传 * @param callback 回调函数 * @constructor */ // callback?: any RoomUpdate(bn_user_name: string, callback?: any) { const param = { bn_user_name: bn_user_name, }; console.log('ws事件room参数', param); this.socket.emit('room_update', param); //回调函数中传入最新获取到的值 this.socket.on('room_update', (res) => { console.log('room列表(room_update)', res); if (typeof res !== 'string') { callback(res); } }); } /** * @description 房间内的消息更新 * @param roomId 房间id ,必传 * @param callback 回调函数 * @constructor */ MessageUpdate(roomId: string, callback?: any) { const param = { room_id: roomId, }; console.log('ws事件参数', param); this.socket.emit('room_message_update', param); //回调函数中传入最新获取到的值 this.socket.off('room_message_update'); //避免重复订阅 this.socket.on('room_message_update', (res) => { console.log('房间消息(room_message_update)', res); if (typeof res !== 'string') { callback(res); } }); } /** * @description 最后一条消息更新 * @param bn_user_name 当前登录人 邮箱 ,必传 * @param callback 回调函数 * @constructor */ LastMessageUpdate(bn_user_name, callback?: any) { const param = { bn_user_name: bn_user_name, }; //回调函数中传入最新获取到的值 console.log('ws事件最后一条消息参数', param); this.socket.emit('last_message_update', param); this.socket.off('last_message_update'); //避免重复订阅 this.socket.on('last_message_update', (res) => { console.log('最后一条消息(last_message_update)', res); if (typeof res !== 'string') { callback(res); } }); } } export const socketService = new SocketService(); export const socket = socketService.socket; export const state = socketService.state;
在生命周期中使用和注销:(注意:这里一定要注销,我在测试时遇到了游览器偶尔能注册连接ws,多数情况下注册不了就是这个原因)
mounted() {
socketService.connect();
},
unmounted() {
console.log('distory');
socketService.disconnect();
},
监听房间内的消息
listenMessages(roomId) { socketService.MessageUpdate(roomId, (messages) => { if (messages) { const rawRoom = this.rooms.find((r) => r.roomId === roomId); if (rawRoom) { messages.forEach((message) => { //message是对话窗口里面的所有消息值 const formattedMessage = this.formatMessage(rawRoom, message); const messageIndex = this.messages.findIndex((m) => m._id === message.id); if (messageIndex === -1) { //只有两个窗口登录人为同一个人,给某个人发消息是才会出现-1的情况 // console.log('[listenMessages] new formatted message:' + JSON.stringify(formattedMessage)); this.messages = this.messages.concat([formattedMessage]); } else { this.messages[messageIndex] = formattedMessage; this.messages = [...this.messages]; } // this.markMessagesSeen(room, message); }); } } }); },
监听左侧房间list
listenRooms() { socketService.RoomUpdate(this.currentUserId, (rooms) => { rooms.forEach((room) => { const foundRoom = this.rooms.find((r) => r.roomId === room.id); if (JSON.stringify(this.rooms) !== '[]') { //判空 if (foundRoom) { //正在编辑的用户,该功能暂时用不上 foundRoom.typingUsers = room.typingUsers; //最后一次更新时间 foundRoom.index = room.lastUpdated.seconds; } else { /** * 更新房间,这里不是使用实时刷新的方案,因为这里要在原有的房间list上追加新房间不像追加消息那么简单, * 需要重新获取很多信息(最后一条消息、格式化房间、房间内用户信息等)。所以这里采用的是重新加载本组件的方案。 **/ // createMessage.loading('对话窗口更新中...'); this.$emit('refresh-chat', new Date().getTime()); this.fetchMoreRooms(); } } }); }); },
监听最后一条消息,如果有消息更新,只返回更新的消息。所以在第一次进入组件时,需要从接口请求获取所有房间的最后一条消息list。
listenLastMessage() { socketService.LastMessageUpdate(this.currentUserId, (messages) => { messages && messages.forEach((message) => { const rawRoom = this.rooms.find((r) => r.roomId === message.room_id); if (rawRoom) { const lastMessage = this.formatLastMessage(message, rawRoom); const roomIndex = this.rooms.findIndex((r) => rawRoom.roomId === r.roomId); this.rooms[roomIndex].lastMessage = lastMessage; this.rooms = [...this.rooms]; } }); if (this.loadingLastMessageByRoom < this.rooms.length) { this.loadingLastMessageByRoom++; if (this.loadingLastMessageByRoom === this.rooms.length) { this.loadingRooms = false; this.roomsLoadedCount = this.rooms.length; } } }); },
这个事件是用于获取左侧房间list的
async fetchMoreRooms() { // 判断是否在房间列表的最底部 if (this.endRooms && !this.startRooms) { this.roomsLoaded = true; return; } console.info('[fetchMoreRooms]Current user id:' + this.currentUserId); console.info('[fetchMoreRooms]Rooms per page:' + this.roomsPerPage); console.info('[fetchMoreRooms]Start rooms:' + this.startRooms); // firebase逻辑 // const query = firestoreService.roomsQuery(this.currentUserId, this.roomsPerPage, this.startRooms); // console.log(query); //替换逻辑:获取所有房间room的list let data = []; if (this.currentUserId) { let temp = await getChatUsersRooms({ bn_user_name: this.currentUserId }); data = temp.data; } // firebase逻辑 // const { data, docs } = await firestoreService.getRooms(query); // this.incrementDbCounter('Fetch Rooms', data.length) // console.log(data, docs); console.log('[fetchMoreRooms]Rooms data:', data); this.roomsLoaded = data.length === 0 || data.length < this.roomsPerPage; if (this.startRooms) this.endRooms = this.startRooms; // this.startRooms = docs[docs.length - 1]; this.startRooms = data[data.length - 1]; const roomUserIds = []; //更新目前所有房间的用户 data.forEach((room) => { room.users.forEach((userId) => { const foundUser = this.allUsers.find((user) => user?._id === userId); if (!foundUser && roomUserIds.indexOf(userId) === -1) { roomUserIds.push(userId); } }); }); // this.incrementDbCounter('Fetch Room Users', roomUserIds.length) let rawUsers = []; //查询用户信息,并将所有用户的信息更新到allUsers for (const userId of roomUserIds) { //查询用户信息的接口 let temp = await getChatUserInfo({ id: userId }); let promise = temp.data; rawUsers.push(promise); } this.allUsers = [...this.allUsers, ...rawUsers]; const roomList = { }; //通过allUsers里面的用户id和接口返回的数据的用户id对比,更新房间list的信息 data.forEach((room) => { roomList[room.id] = { ...room, users: [] }; room.users.forEach((userId) => { const foundUser = this.allUsers.find((user) => user?._id === userId); if (foundUser) roomList[room.id].users.push(foundUser); }); }); const formattedRooms = []; Object.keys(roomList).forEach((key) => { const room = roomList[key]; const roomContacts = room.users.filter((user) => user._id !== this.currentUserId); room.roomName = roomContacts.map((user) => user.username).join(', ') || '我自己'; const roomAvatar = roomContacts.length === 1 && roomContacts[0].avatar ? roomContacts[0].avatar : logoAvatar; formattedRooms.push({ ...room, roomId: key, avatar: roomAvatar, index: room.lastUpdated.seconds, lastMessage: { content: 'Room created', timestamp: formatTimestamp(new Date(room.lastUpdated.seconds), room.lastUpdated), }, }); }); this.rooms = this.rooms.concat(formattedRooms); //第一次进入获取一次最后一条消息的接口数据 if (this.currentUserId) { getChatLastMessage({ bn_user_name: this.currentUserId }).then((messages) => { messages.data.forEach((message) => { const rawRoom = this.rooms.find((r) => r.roomId === message.sender_id); const lastMessage = this.formatLastMessage(message, rawRoom); const roomIndex = this.rooms.findIndex((r) => rawRoom.roomId === r.roomId); this.rooms[roomIndex].lastMessage = lastMessage; this.rooms = [...this.rooms]; if (this.loadingLastMessageByRoom < this.rooms.length) { this.loadingLastMessageByRoom++; if (this.loadingLastMessageByRoom === this.rooms.length) { this.loadingRooms = false; this.roomsLoadedCount = this.rooms.length; } } }); }); } if (!this.rooms.length) { this.loadingRooms = false; this.roomsLoadedCount = 0; } // console.info('[fetchMoreRooms]Formatted Rooms data:' + JSON.stringify(formattedRooms)); console.info('[fetchMoreRooms]Rooms Loaded count:' + this.roomsLoadedCount); // console.info('[fetchMoreRooms]Listen users online status:' + JSON.stringify(formattedRooms)); // this.listenUsersOnlineStatus(formattedRooms); // console.info('[fetchMoreRooms]Listen rooms:' + JSON.stringify(query)); // this.listenRooms(query); // setTimeout(() => console.log('TOTAL', this.dbRequestCount), 2000) //注册ws事件 this.listenRooms(); this.listenLastMessage(); },
这个事件用于获取、格式化房间内的历史消息
fetchMessages({
room, options = {
} }) {
this.$emit('show-demo-options', false);
this.room = room;
// 如果是第一次打开就初始化房间的参数
if (options.reset) {
this.resetMessages();
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。