概述
MessageList 组件是聊天界面的核心组件,负责展示消息列表并提供丰富的交互功能。它支持消息聚合、自动滚动、历史消息加载、已读回执等高级特性,适用于构建高度可定制的聊天界面。组件内部处理滚动行为、消息加载逻辑和消息分组展示,为用户提供流畅的消息浏览体验。
功能特性
消息展示:支持多种消息类型(文本、图片、视频、文件、自定义消息等)的渲染和显示。
消息聚合:根据时间间隔和发送者自动聚合相邻消息。
智能滚动:自动滚动到底部,支持手动滚动控制。
历史加载:上拉加载更多历史消息。
已读回执:支持消息已读状态显示。
消息操作:支持撤回、删除等消息操作。
自定义渲染:支持自定义消息组件和时间分割线组件。
快速使用
以下示例代码是 MessageList 最简单的用法。
<template><UIKitProvider><Chat><MessageList /><MessageInput /></Chat></UIKitProvider></template><script lang="ts" setup>import { UIKitProvider, Chat, MessageList, MessageInput } from '@tencentcloud/chat-uikit-vue3';</script>
实践建议:
1. MessageList 组件需要放在 UIKitProvider、Chat 容器中使用。
2. MessageList 建议和 MessageInput 组件搭配使用。
Props 字段速查表
字段 | 类型 | 默认值 | 描述 |
'left' | 'right' | 'two-sided' | 'two-sided' | 消息的对齐方式,支持左对齐、右对齐和双边对齐。 | |
boolean | false | 是否启用消息已读回执功能。 | |
MessageAction[] | undefined | 自定义消息操作列表,例如撤回、删除等。 | |
number | 300 (秒) | 消息聚合的时间间隔(秒),在此时间内发送的同一发送者的消息会被聚合。设置为 0 可禁用消息聚合。 | |
(message: MessageInfo) => boolean | undefined | 自定义消息过滤函数,用于控制哪些消息应该显示。 | |
boolean | false | 是否启用消息已读回执功能。 | |
Component | undefined | 自定义消息组件,用于渲染单条消息。 | |
Component | undefined | 自定义消息时间分割线组件。 |
Props 详细介绍
alignment
类型:'left' | 'right' | 'two-sided'
详细说明:消息在列表中的对齐方式。
'left' 表示所有消息左对齐,'right' 表示所有消息右对齐,'two-sided' 表示发送方消息右对齐,接收方消息左对齐。默认值为 'two-sided'。messageAggregationTime
类型:number
详细说明:消息聚合的时间间隔,单位为秒。当同一发送者在指定时间间隔内连续发送多条消息时,这些消息将被聚合显示。设置为
0 或更小的值将禁用消息聚合功能,每条消息都会独立显示。默认值为 300 (5分钟)。enableReadReceipt
类型:boolean
详细说明:是否启用消息的已读回执功能。当设置为
true 时,组件将尝试显示消息的已读状态。默认值为 false。messageActionList
类型:MessageAction[]
详细说明:用于定义在消息上可以执行的自定义操作列表,例如复制、撤回、转发、删除等。这是一个复杂类型,可以通过传入一个
MessageAction 对象数组来定制消息的操作行为。默认值为 undefined,组件内部会根据 useMessageActions 钩子提供默认的操作列表。目前默认的顺序是:
['copy', 'recall', 'quote', 'forward', 'delete']。MessageAction 类型定义:
import type { Component } from 'vue';import type { MessageInfo } from '@tencentcloud/chat-uikit-vue3';interface MessageAction {/** 唯一的操作标识符 */key: string;/** 操作的显示文本 */label: string;/** 操作的图标组件或图标名称 */icon?: Component | string;/** 操作点击时的回调函数 */onClick?: (message: MessageInfo) => void;/** 控制操作的可见性,可以是布尔值或一个根据消息决定可见性的函数 */visible?: boolean | ((message: MessageInfo) => boolean);/** 自定义组件,如果提供了,将替代默认的标签和图标 */component?: Component;/** 自定义类名 */className?: string;/** 自定义样式 */style?: Record<string, any>;}
可以使用
useMessageActions 钩子获取完整的消息操作列表,然后根据需要进行自定义。useMessageActions 钩子接收一个可选参数,可以是一个包含操作键(string)或完整 MessageAction 对象的数组。如果传入 string 数组,则会使用默认操作的配置;如果传入 MessageAction 对象,则会合并并覆盖默认配置。代码示例1:变更消息操作列表的顺序
下面的代码将
forward操作放到消息操作列表的第一个。<template><MessageList :messageActionList="actions" /></template><script lang="ts" setup>import { MessageList, useMessageActions } from '@tencentcloud/chat-uikit-vue3';const actions = useMessageActions(['forward', 'copy', 'recall', 'quote', 'delete']);</script>
示例效果:

代码示例2:仅展示部分消息操作
仅展示
copy、recall 操作,其他操作隐藏。<template><MessageList :messageActionList="actions" /></template><script lang="ts" setup>import { MessageList, useMessageActions } from '@tencentcloud/chat-uikit-vue3';const actions = useMessageActions(['copy', 'recall']);</script>
示例效果:

代码示例3:自定义消息操作的样式和逻辑
下面是一个自定义转发操作的示例:
1. 将标签修改为 '转发 ⚠️'
2. 将颜色修改为橙色
3. 只有别人发的消息可以转发
<template><MessageList :messageActionList="actions" /></template><script lang="ts" setup>import { MessageList, useMessageActions } from '@tencentcloud/chat-uikit-vue3';const actions = useMessageActions(['copy', {key: 'forward',label: 'Forward ⚠️',style: {color: 'orange',},visible: (message) => message.isSentBySelf === false,}, 'quote', 'recall', 'delete']);</script>
示例效果:

代码示例4:新增自定义消息操作
假设需要自定义消息操作,例如仅其他人发送的消息可以标记'喜欢',且插入在'撤回'操作之后。
<template><MessageList :messageActionList="actions" /></template><script lang="ts" setup>import { MessageList, useMessageActions } from '@tencentcloud/chat-uikit-vue3';const customLikeAction = {key: 'like',label: 'Like',icon: '🩷',visible: (message) => message.isSentBySelf === false,onClick: (message) => {console.log('like message:', message.msgID);// 在这里实现点赞逻辑,例如调用后端API},};const actions = useMessageActions(['forward', 'copy', 'recall', customLikeAction, 'quote', 'delete']);</script>
示例效果:

filter
type:((message: MessageInfo) => boolean) | undefined
详细说明:一个自定义的过滤函数,用于在消息列表渲染之前对消息进行筛选。该函数接收一个
MessageInfo 类型的消息对象,并返回一个布尔值。如果返回 true,则消息会显示;如果返回 false,则消息不会显示。默认值为 undefined,表示不进行额外过滤(但组件内部会默认过滤掉 isDeleted 为 true 的消息)。代码示例:过滤掉机器人发送的文本消息
这个示例展示了如何使用
filter prop 来过滤掉某些用户发送的特定消息。<template><MessageList :filter="customMessageFilter" /></template><script lang="ts" setup>import { MessageList, MessageType } from '@tencentcloud/chat-uikit-vue3';import type { MessageInfo } from '@tencentcloud/chat-uikit-vue3';// 定义自定义消息过滤函数const customMessageFilter = (message: MessageInfo): boolean => {if (message.nick?.includes('_robot')&& message.messageType === MessageType.Text as any) {return false;}return true;};</script>
Message
类型:Component | undefined
详细说明:用于自定义渲染消息列表中的单个消息组件。
如果您需要完全控制消息的显示样式和内部逻辑,可以传入一个 Vue 组件来替代默认的消息渲染。自定义组件将接收
message 、alignment、messageActionList 等 props。默认值会使用内部的默认消息组件 Message。这个示例展示了如何重写Message 组件实现在自己的消息上显示头像和昵称(默认自己发送的消息不显示头像和昵称)。
<template><MessageList :Message="MessageWithSelfAvatarAndNick" /></template><script lang="ts" setup>import { defineComponent, h } from 'vue';import { MessageList, Message } from '@tencentcloud/chat-uikit-vue3';const MessageWithSelfAvatarAndNick = defineComponent({name: 'MessageWithSelfAvatar',inheritAttrs: false,setup(_, { attrs }) {return () => h(Message as Component, {...attrs,removeAvatar: false,isHiddenMessageNick: false,});},});</script>
MessageTimeDivider
类型:Component | undefined
详细说明:用于自定义渲染时间分割线组件。
您可以传入一个 Vue 组件来替代默认的时间分割线渲染。自定义组件将接收
currentMessage (当前时间分割线关联的消息)、previousMessage (上一条消息) 等 props,可以根据这些信息决定时间分割线的显示逻辑和样式。默认值会使用内部的默认时间分割线组件 MessageTimeDivider。这个示例展示了如何创建一个自定义时间分割线组件,根据消息时间判断是否为工作时间,并显示相应的标签和颜色。
<template><MessageList :MessageTimeDivider="BusinessTimeDivider" /></template><script lang="ts" setup>import { defineComponent, h } from 'vue';import { MessageList } from '@tencentcloud/chat-uikit-vue3';import type { MessageInfo } from '@tencentcloud/chat-uikit-vue3';const BusinessTimeDivider = defineComponent({name: 'BusinessTimeDivider',props: {previousMessage: {type: Object as PropType<MessageInfo | undefined>,default: undefined,},currentMessage: {type: Object as PropType<MessageInfo>,required: true,},},setup(props) {return () => {if (!props.previousMessage || !props.currentMessage) {return null;}const currentTime = props.currentMessage.timestamp ?? new Date();const previousTime = props.previousMessage.timestamp ?? new Date();const shouldShow = currentTime.toDateString() !== previousTime.toDateString()|| currentTime.getTime() - previousTime.getTime() > 4 * 60 * 60 * 1000;if (!shouldShow) {return null;}const hour = currentTime.getHours();const day = currentTime.getDay();const isWorkingTime = day >= 1 && day <= 5 && hour >= 9 && hour <= 18;return h('div', { class: 'message-props-demo__time-divider' }, [h('span',{class: isWorkingTime? 'message-props-demo__time-label message-props-demo__time-label--work': 'message-props-demo__time-label message-props-demo__time-label--off',},isWorkingTime ? '工作时间' : '非工作时间',),currentTime.toLocaleString(),]);};},});</script>