当前位置:   article > 正文

vue-advanced-chat使用指南(socket.io+node+vue实现聊天)

vue-advanced-chat

demo地址:—
vue-advanced-chat的git地址:https://github.com/advanced-chat/vue-advanced-chat

1.搭建demo

demo地址克隆后在demo目录安装依赖并启动
在这里插入图片描述
启动之后的页面如下:
在这里插入图片描述

2.前端代码分析

在这里插入图片描述

2.1 重点api分析

current-user-id:当前用户id

room-id:可随时加载特定房间?

rooms:?

messages:消息列表

room-actions:可用于在单击房间列表中每个房间的下拉图标时显示您自己的按钮

配合事件room-action-handler使用

roomActions: [
{
    name: 'inviteUser', title: '测试下拉' },
{
    name: 'removeUser', title: 'Remove User' },
{
    name: 'deleteRoom', title: 'Delete Room' }
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述

menu-actions:可用于在单击房间内的垂直点图标时显示您自己的按钮

配合事件menu-action-handler使用

menuActions: [
{
    name: 'inviteUser', title: '测试菜单' },
{
    name: 'removeUser', title: 'Remove User' },
{
    name: 'deleteRoom', title: 'Delete Room' }
],
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述

message-selection-actions:选择消息时,您可以使用它在房间标题中显示自定义操作按钮

messageSelectionActions: [{
    name: 'deleteMessages', title: '你确定要删除嘛?' }]
  • 1
  • 2

在这里插入图片描述

templates-text:可用于/在房间文本区域中输入内容时添加自动完成模板文本

templatesText: [
				{
   
					tag: '吃好',
					text: '吃好喝好,一路走好!'
				},
				{
   
					tag: 'action',
					text: 'This is the action'
				},
				{
   
					tag: 'action 2',
					text: 'This is the second action'
				}
			],
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述

text-messages:可用于替换默认的 i18n 文本

textMessages: {
   
	ROOMS_EMPTY: '无聊天',
	ROOM_EMPTY: '未选中聊天',
	NEW_MESSAGES: '新消息',
	MESSAGE_DELETED: '消息已删除',
	MESSAGES_EMPTY: '无消息',
	CONVERSATION_STARTED: '聊天开始于:',
	TYPE_MESSAGE: '请输入',
	SEARCH: '搜索',
	IS_ONLINE: '在线',
	LAST_SEEN: 'last seen ',
	IS_TYPING: '正在输入...',
	CANCEL_SELECT_MESSAGE: '取消'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述

2.2 重点事件分析

fetch-more-rooms ?

向下滚动房间列表时触发,应该是实现分页系统的方法

fetch-messages

每次打开房间时都会触发。如果房间是第一次打开,options参数将保持reset: true。(其目的是当用户滚动到顶部时加载对话的较旧消息)

fetchMessages({
     room, options = {
    } }) {
   
this.$emit('show-demo-options', false)

  //如果是第一次打开就初始化房间的参数
if (options.reset) {
   
this.resetMessages()
}

if (this.previousLastLoadedMessage && !this.lastLoadedMessage) {
   
this.messagesLoaded = true
return
}

  //设置当前选中的房间的id值
this.selectedRoom = room.roomId

console.info('[fetchMessages] Selected Room(选中的房间id):' + this.selectedRoom)
console.info('[fetchMessages] Selected Room messages per page(选中房间消息页码):' + this.messagesPerPage)
console.info('[fetchMessages] Selected Room last loaded message(选中房间最后加载的消息):' + this.lastLoadedMessage)
firestoreService
.getMessages(room.roomId, this.messagesPerPage, this.lastLoadedMessage)
.then(({
     data, docs }) => {
   
	// this.incrementDbCounter('Fetch Room Messages', messages.length)

      //判空
	if (this.selectedRoom !== room.roomId) return

      //从接口获取到的消息数据为空,或者拿到的数据长度小于本地消息长度,就显示loading
	if (data.length === 0 || data.length < this.messagesPerPage) {
   
		setTimeout(() => {
   
			this.messagesLoaded = true
		}, 0)
	}
      
      //如果是第一次打开就将消息变量messages置为空
	if (options.reset) this.messages = []

	data.forEach(message => {
   
        //格式化消息为模板消息
		const formattedMessage = this.formatMessage(room, message)
		console.info('[fetchMessages] Formatted Message(格式化后的消息):' + JSON.stringify(formattedMessage))
		this.messages.unshift(formattedMessage)
	})
	console.info('[fetchMessages] Fetch Room Messages Length(获取到的消息长度):' + this.messages.length)
      
	if (this.lastLoadedMessage) {
   
		this.previousLastLoadedMessage = this.lastLoadedMessage
	}
	this.lastLoadedMessage = docs[docs.length - 1]

	this.listenMessages(room)
})
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

send-message

发送消息,点击发送或者enter时触发

async sendMessage({
     content, roomId, files, replyMessage }) {
   
  //content消息内容 、 roomId房间id 、files文件 、replyMessage(微信引用)回复的消息
const message = {
   
sender_id: this.currentUserId,
content,
timestamp: new Date()
}

if (files) {
   
message.files = this.formattedFiles(files)
}

if (replyMessage) {
   
message.replyMessage = {
   
	_id: replyMessage._id,
	content: replyMessage.content,
	sender_id: replyMessage.senderId
}

if (replyMessage.files) {
   
	message.replyMessage.files = replyMessage.files
}
}
console.info('[sendMessage] room id is(发送消息的房间id):' + roomId)
console.info('[sendMessage] message is:' + JSON.stringify(message))

const {
    id } = await firestoreService.addMessage(roomId, message)

console.info('[sendMessage] message id is:' + id)

if (files) {
   
for (let index = 0; index < files.length; index++) {
   
	await this.uploadFile({
    file: files[index], messageId: id, roomId })
}
}
console.info('[sendMessage] update room with id:' + roomId)
firestoreService.updateRoom(roomId, {
    lastUpdated: new Date() })
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

edit-message

编辑消息

async editMessage({
     messageId, newContent, roomId, files }) {
   
const newMessage = {
    edited: new Date() }
newMessage.content = newContent

if (files) {
   
	newMessage.files = this.formattedFiles(files)
} else {
   
	newMessage.files = firestoreService.deleteDbField
}

await firestoreService.updateMessage(roomId, messageId, newMessage)

if (files) {
   
	for (let index = 0; index < files.length; index++) {
   
		if (files[index]?.blob) {
   
			await this.uploadFile({
    file: files[index], messageId, roomId })
		}
	}
}
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

delete-message

删除消息

async deleteMessage({
     message, roomId }) {
   
	await firestoreService.updateMessage(roomId, message._id, {
   
		deleted: new Date()
	})

	const {
    files } = message

	if (files) {
   
		files.forEach(file => {
   
			storageService.deleteFile(this.currentUserId, message._id, file)
		})
	}
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

open-file

下载文件

openFile({
     file }) {
   
	window.open(file.file.url, '_blank')
},
  • 1
  • 2
  • 3
  • 4
  • 5

open-user-tag ?这个应该用不到

当点击消息内的用户标签时触发。通过@在页脚文本区域中输入并发送消息来创建用户标签
在这里插入图片描述

add-room

添加房间
在这里插入图片描述

addRoom() {
   
	this.resetForms()
	this.addNewRoom = true
},
  • 1
  • 2
  • 3
  • 4
  • 5

room-action-handler、menu-action-handler

配合api中的room-actions、menu-actions一起使用

menuActionHandler({
     action, roomId }) {
   
switch (action.name) {
   
case 'inviteUser':
	return this.inviteUser(roomId)
case 'removeUser':
	return this.removeUser(roomId)
case 'deleteRoom':
	return this.deleteRoom(roomId)
}
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

message-selection-action-handler

配合api中的message-selection-actions使用

messageSelectionActionHandler({
     action, messages, roomId }) {
   
switch (action.name) {
   
	case 'deleteMessages':
		messages.forEach(message => {
   
			this.deleteMessage({
    message, roomId })
		})
}
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

send-message-reaction

单击消息内的表情符号图标

async sendMessageReaction({
     reaction, remove, messageId, roomId }) {
   
	firestoreService.updateMessageReactions(
		roomId,
		messageId,
		this.currentUserId,
		reaction.unicode,
		remove ? 'remove' : 'add'
	)
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

typing-message

开始输入消息(在对方可以看到“正在输入中。。。”的提示)

typingMessage({
     message, roomId }) {
   
	if (roomId) {
   
		if (message?.length > 1) {
   
			this.typingMessageCache = message
			return
		}

		if (message?.length === 1 && this.typingMessageCache) {
   
			this.typingMessageCache = message
			return
		}

		this.typingMessageCache = message

		firestoreService.updateRoomTypingUsers(
			roomId,
			this.currentUserId,
			message ? 'add' : 'remove'
		)
	}
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

toggle-rooms-list

单击房间标题内的切换图标

2.3 公用函数

resetMessages()

重置房间的消息基础变量

resetMessages() {
   
	this.messages = []
	this.messagesLoaded = false
	this.lastLoadedMessage = null
	this.previousLastLoadedMessage = null
	this.listeners.forEach(listener => listener())
	this.listeners = []
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

formatMessage()

格式化消息模板

formatMessage(room, message) {
   
// const senderUser = room.users.find(user => user._id === message.sender_id)
const formattedMessage = {
   
	...message,
	...{
   
		senderId: message.sender_id,
		_id: message.id,
		seconds: message.timestamp.seconds,
		timestamp: parseTimestamp(message.timestamp, 'HH:mm'),
		date: parseTimestamp(message.timestamp, 'DD MMMM YYYY'),
		username: room.users.find(user => message.sender_id === user._id)
			?.username,
		// avatar: senderUser ? senderUser.avatar : null,
		distributed: true
	}
}

if (message.replyMessage) {
   
	formattedMessage.replyMessage = {
   
		...message.replyMessage,
		...{
   
			senderId: message.replyMessage.sender_id
		}
	}
}

return formattedMessage
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

listenMessages() ?

listenMessages(room) {
   
const listener = firestoreService.listenMessages(
room.roomId,
this.lastLoadedMessage,
this.previousLastLoadedMessage,
messages => {
   
messages.forEach(message => {
   
	const formattedMessage = this.formatMessage(room, message)
	const messageIndex = this.messages.findIndex(
		m => m._id === message.id
	)

	if (messageIndex === -1) {
   
		console.log('[listenMessages] new formatted message:' + JSON.stringify(formattedMessage))
		this.messages = this.messages.concat([formattedMessage]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/770743
推荐阅读
相关标签
  

闽ICP备14008679号