测试代码:https://github.com/robinfoxnan/vue-advanced-chat-test0
控件源码:https://github.com/advanced-chat/vue-advanced-chat
先上个效果图:
这个控件就是专门为聊天而设计的,但是也有一些不足:
1)有些引用的控件已经过期了,还有些内存泄漏;
2)示例的demo使用的google的firebase存储,运行不起来;
文档写的太粗糙,所以折腾了一个上午,用内存数据测试了一下显示效果。
要点如下:
1)聊天室(会话)需要设置各种属性:
<template>
<vue-advanced-chat
ref="chat"
:current-user-id="currentUserId" // 当前用户ID
:rooms="JSON.stringify(rooms)" // 会话列表
:messages="roomMessages" // 当前会话的消息列表
:menu-actions="JSON.stringify(menuActions)" // 右侧...的菜单
// 消息有4个下拉菜单
:message-selection-actions="JSON.stringify(messageSelectionActions)"
:loading-rooms="loadingRooms" // bool类型,是否正在加载会话列表
:rooms-loaded="messagesLoaded" // bool类型,会话加载完毕,不在拉动加载
:room-id="roomId" // 最初的会话ID
:room-message="roomMessage" // 这个是个字符串,没有发现用法
:messages-loaded = "true" // 消息更新完以后,设置为true则不再动画转圈
@add-room="addRoom($event.detail[0])" // 添加一个会话按钮的回调
@fetch-messages="fetchMessages($event.detail[0])" // 切换会话时候会触发加载消息的回调
@send-message="sendMessage($event.detail[0])" // 点击发送按钮时候触发发送动作
/>
</template>
2)会话的格式如下:
rooms: [{
roomId: '1',
roomName: '飞鸟 的聊天',
avatar: icons[0],
unreadCount: 1,
lastUpdated: Date.now(),
index: 1,
lastMessage: {
_id: '1',
content: '在么?在么?',
senderId: '1',
username: '小花儿',
timestamp: '10:20',
saved: true,
distributed: false,
seen: true,
new: true
},
users: [
users["1"], users["2"]
],
typingUsers: [ '1' ]
},
{
roomId: '2',
roomName: '群聊',
avatar: icons[1],
unreadCount: 4,
lastUpdated: Date.now(),
index: 2,
lastMessage: {
_id: '2',
content: '昨天我们做了一个测试……',
senderId: '1',
username: '飞鸟',
timestamp: '10:20',
saved: true,
distributed: false,
seen: true,
new: true
},
users: [ users["1"], users["2"]
],
typingUsers: [ '2' ]
}
],
3)消息的格式如下:
const aMsg ={
_id: '1',
indexId: 1,
content: '小花发送的测试消息',
senderId: users["1"]._id,
username: users["1"].username,
avatar: users["1"].avatar,
date: '13 November',
timestamp: '10:20',
system: false,
saved: true,
distributed: true,
seen: true,
deleted: false,
failure: false,
disableActions: false,
disableReactions: false,
};
4) 会话的消息的需要动态加载的:
// 点击了聊天会话,会触发这个回调函数,在这里加载消息
fetchMessages({ room, options = {} }) {
this.messagesLoaded = false;
this.$emit('show-demo-options', false)
if (options.reset) {
//this.resetMessages()
}
console.log("选项:" +options);
console.log("选中会话:" +room.roomId);
this.roomMessages = roomMsgMap[room.roomId]
this.messagesLoaded = true
},
5) 发送消息动作:
带有附件的其实要先上传,上传完毕后,将远端的url赋值给url就认为是发送完毕了,不再显示动画了;否则一直转圈,显示发送中;
// 点击了发送按钮,则执行发送消息
async sendMessage({ content, roomId, files, replyMessage }) {
console.log("当前发送消息到对话:" + roomId );
this.currentMsgSeq = this.currentMsgSeq + 1;
const u = users[this.currentUserId];
const message = {
_id : this.currentMsgSeq.toString(),
senderId: this.currentUserId,
username: u.username,
avatar: u.avatar,
content: content,
timestamp: formatDate(new Date()),
date: '13 November',
system: false,
saved: true,
distributed: true,
seen: true,
deleted: false,
failure: false,
disableActions: false,
disableReactions: false,
}
if (files) {
message.files = this.formattedFiles(files)
console.log(files);
}
if (replyMessage) {
message.replyMessage = {
_id: replyMessage._id,
content: replyMessage.content,
sender_id: replyMessage.senderId
}
if (replyMessage.files) {
message.replyMessage.files = replyMessage.files
}
}
this.messagesLoaded = false
roomMsgMap[roomId].push(message);
// console.log(roomMsgMap[roomId]);
this.roomMessages = [...roomMsgMap[roomId]]
// 注意,下面的用法不行,不刷新
//this.roomMessages = roomMsgMap[roomId]
console.log(this.roomMessages);
this.messagesLoaded = true
},
formattedFiles(files) {
const formattedFiles = []
files.forEach(file => {
const messageFile = {
name: file.name,
size: file.size,
type: file.type,
extension: file.extension || file.type,
url: file.url || file.localUrl
// 注意,这里设置了HTTP的图片地址后,能正确加载,证明上传完毕,上传过程就停止了,不转了
//url :"https://img0.baidu.com/it/u=1746301175,572912059&fm=253&fmt=auto&app=120&f=JPEG?w=580&h=500"
}
if (file.audio) {
messageFile.audio = true
messageFile.duration = file.duration
}
formattedFiles.push(messageFile)
})
return formattedFiles
},
其他的我也没有测试呢。
有兴趣一起做即时通信的朋友可以私聊。