Skip to content

BubbleList 气泡列表

使用import { BubbleList } from 'vue-element-plus-x'
文档
编辑此页更新日志Issue 反馈

介绍

BubbleList 基于 Bubble 组件,用于展示一组对话气泡列表。内置虚拟滚动(virtua/vue)、自动追底、滚动状态机、未读计数、双向分页加载、回底按钮和混合节点渲染,开箱即用,按需配置。

代码演示

基础使用

通过 list 数组快速渲染一组对话气泡。数组中每个对象会透传给内置的 Bubble 组件,Bubble 的所有属性(contentplacementloadingshapevariant 等)都可以直接配置,消息的增删改只需维护这个数组即可。

💡 Tip

通过 max-height 属性或父容器高度控制列表高度,内容溢出时自动出现滚动条。每个 item 的详细属性可参考 Bubble 文档

滚动控制方法

iV2 自动追底规则autoScroll 开启时(默认),追加消息会自动触底,未读计数始终为 0。
如需体验未读角标 + 回底按钮,请先将下方开关关闭 autoScroll,再手动向上滚动后追加消息——视图不动、未读 +1、回底按钮浮现,这正是 V2 状态机的核心体验。
autoScroll:
开启(自动追底)
滚动状态AT_BOTTOM
未读计数0
消息总数0
目标索引0

通过组件实例的三个方法精确控制滚动位置:scrollToTop()scrollToBottom()scrollToBubble(index),均支持传入 smooth 参数控制是否平滑滚动。

同时暴露 currentScrollStatecurrentUnreadCount 实例属性,也可监听 @scroll-state-change / @unread-count-change 事件实时感知状态(AT_BOTTOM / SCROLLED_UP / HAS_NEW_MESSAGES)。

自动触底控制

⚙️AutoScroll 自动触底控制台
autoScroll已开启 — 新消息自动触底
开启
当前模式:自动追底
所有新消息(用户 / AI)都会自动滚动到底部,未读计数始终为 0。 尝试向上滚动后再点追加消息,观察是否仍然自动回底。
scrollStateAT_BOTTOM
unreadCount0
autoScrollON

autoScroll(默认 true)控制追加新消息时是否自动滚到底部。关闭后,新消息不再自动触底,而是累计未读计数——这是显示未读角标的前提。

流式输出的特殊行为

即使 autoScroll 开启,流式增量也只在用户处于底部时跟随;上滑后不强制拉回,避免打断阅读。

返回底部按钮

核心控制
autoScroll已开启 — 新消息自动触底,无未读
开启
自定义插槽 (V2)
默认按钮
滚动条显示
鼠标悬停
内置按钮样式
Loading 动效
开启
按钮颜色
图标大小
按钮定位 插槽模式也生效
距底部 %
20%
水平位置 %
50%
autoScroll 开启中
追加消息后自动滚到底部,unreadCount 始终为 0,回底按钮不会出现。
尝试:先向上滚动一段距离,再点「+ 用户消息」,观察是否仍自动回底。
scrollStateAT_BOTTOM
unreadCount0
autoScrollON
按钮模式内置默认

内置回底按钮,支持属性配置外观,也可通过 #backToBottom 插槽完全自定义。

通过 showBackButtonbackButtonThresholdbackButtonPositionbtnColor / btnIconSize / btnLoading 等属性调整按钮行为与样式。关闭 autoScroll 后,按钮上会自动出现未读角标,插槽上下文中的 unreadCount 即为当前未读数,scrollToBottom() 调用后自动清零。

流式跟随

~核心体验流程:① 点"开始流式回复" → ② 等 AI 开始输出 → ③ 向上滚动打断 → ④ 观察未读增加、列表不再跳动 → ⑤ 点"回到底部恢复" → ⑥ 观察后续 chunk 自动跟随
滚动状态AT_BOTTOM
未读计数0
流式状态空闲
当前轮次0
已输出字符0/0
运行 tick0/120
最近动作点击"开始流式回复",然后上滑观察跟随中断,回到底部观察自动恢复。

autoScroll 开启(默认)时,流式输出内容变高会自动贴底。用户上滑后跟随中断,回到底部后自动恢复——无需任何额外配置。

自定义追底策略

如需自定义跟随逻辑(例如只有本端消息才强制追底),可通过 shouldFollowContent 回调接管决策。回调参数中的 reason 字段告知本次触发来源:own-message(本端发送)、streaming(流式增量)、new-message(新追加消息)。

双向分页加载

向上滚动到顶部触发历史加载,再向下滚动到底部触发更多消息。观察边界状态区的 loading → no-more 切换。
滚动状态AT_BOTTOM
未读计数0
顶部触发次数0
底部触发次数0
历史批次0/3
底部批次0/2
最近动作手动滚动到顶部触发历史加载,回到底部继续向下滚动可触发更多消息。 顶部加载中:否,底部加载中:否

向上滚到顶部触发 @load-more-top,向下滚到底部触发 @load-more-bottom。数据准备完毕后调用 loadMoreTopComplete() / loadMoreBottomComplete() 通知组件,滚动位置自动修复,无需手动处理跳动。

通过 topStatus / bottomStatus 属性({ type, text })控制边界状态区的展示(loading / no-more),配合 #topStatus / #bottomStatus 插槽自定义 UI。

混合节点

混合节点 / 统一 item 插槽

普通消息继续使用默认 Bubble 渲染;当 item 中包含特殊标识符时,统一走 #item 插槽。 这里演示日期节点、历史分隔节点和系统提示节点共存于同一条时间线里。

滚动状态AT_BOTTOM
未读计数0
节点总数0

列表中除气泡消息外,可以混入任意类型的节点(日期分隔线、系统提示、历史加载标记等)。通过 itemType 属性或解析函数标记非气泡节点,命中后走 #item 插槽渲染,普通消息仍走默认 Bubble。

插槽上下文 { item, index, itemType } 用于区分节点类型,渲染不同 UI。虚拟滚动中特殊节点的高度同样会自动测量。

插槽自定义

动态设置内容
自定义 loading

通过 9 个插槽完全接管列表渲染:#avatar#header#content#footer#loading 控制每条气泡的各部分;#backToBottom 自定义回底按钮(含未读角标);#topStatus / #bottomStatus 自定义边界状态区;#item 渲染非气泡类型节点。

自定义主题

通过 ConfigProvider.themeOverrides 覆盖 BubbleList 的主题变量。完整变量表与可复制模板见:

滚动列表,观察最大高度与返回按钮尺寸变化。
第 1 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 2 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 3 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 4 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 5 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 6 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 7 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 8 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 9 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 10 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 11 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 12 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 13 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 14 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 15 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 16 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 17 条消息:用于演示 BubbleList 的滚动与返回按钮。
第 18 条消息:用于演示 BubbleList 的滚动与返回按钮。

通过 ConfigProvider.themeOverrides 覆盖 BubbleList--elx-* 变量,并联动 Bubble 的主题变量,开关前后会有明显反差。

与 x-markdown-vue 结合使用

v2.0.0 开始,组件库不再内置 XMarkdown / XMarkdownAsync。如需 Markdown 渲染,请使用独立包 x-markdown-vue,或查看专属文档:XMarkdown

安装

bash
pnpm add x-markdown-vue
pnpm add katex
pnpm add shiki shiki-stream

💡 Tip

如果需要代码块语法高亮功能,请安装 shikishiki-stream。否则控制台可能会报错:Streaming highlighter initialization failed: Error: Failed to load shiki-stream module

基础用法

先点击"开始流式 Markdown",然后尝试向上滚动打断跟随,再点"回到底部恢复"观察自动恢复。
滚动状态AT_BOTTOM
未读计数0
流式状态空闲
已输出字符0/0
当前轮次0
最近动作点击"开始流式 Markdown",观察 AI 消息逐段渲染与滚动跟随效果。

支持公式、代码块、任务列表的列表渲染,并模拟 AI 逐段输出 Markdown 的实时效果。

V2 版本升级提示

  • 流式跟随:V2 在流式输出(内容持续变高)时,自动贴底跟随。用户上滑后中断,回到底部后自动恢复。V1 需要手动管理滚动位置。
  • 虚拟滚动兼容:V2 虚拟滚动 + 动态高度测量,流式变高时自动重新测量 item 高度,不会出现滚动位置跳动。
  • 状态感知:通过 scroll-state-changeunread-count-change 事件可实时感知流式输出期间的滚动状态变化。

雾化效果

通过 enable-animate 属性实现打字机雾化效果,模拟 AI 流式输出场景。

属性

属性名类型是否必填默认值说明
listArray-消息数组,每个对象透传给内置 Bubble 组件,支持所有 Bubble 属性。
autoScrollBooleantrue追加新消息时是否自动滚到底部。关闭后新消息累计未读计数。
maxHeightString-列表最大高度,默认撑满父容器。
virtualBooleantrue是否开启虚拟滚动(基于 virtua/vue),大数据量场景推荐保持开启。
smoothScrollBooleanfalse编程式滚动是否默认使用平滑动画。
itemKeystring | Function'key'节点唯一标识,可传字段名或 (item, index) => key 函数。
itemTypestring | Function-非气泡节点类型标识,命中后走 #item 插槽渲染;可传字段名或函数。
showBackButtonBooleantrue是否显示回底按钮。
backButtonThresholdNumber80触发显示回底按钮的阈值(距底部 px)。
backButtonPositionObject{ bottom: '20px', left: 'calc(50% - 19px)' }回底按钮的 CSS 定位,可配置 top / right / bottom / left / transform
backButtonSmoothScrollBooleantrue点击回底按钮时是否平滑滚动。
alwaysShowScrollbarBooleanfalse是否一直显示滚动条。
btnLoadingBooleantrue是否在内置回底按钮上显示 loading 状态。
btnColorString'#409EFF'内置回底按钮颜色。
btnIconSizeNumber24内置回底按钮图标大小(px)。
topStatus{ type, text? }-顶部边界状态,type 可选 idle / loading / no-more / error
bottomStatus{ type, text? }-底部边界状态,同 topStatus
loadMoreTopThresholdNumber100触发 @load-more-top 的距顶阈值(px)。
loadMoreBottomThresholdNumber100触发 @load-more-bottom 的距底阈值(px)。
shouldFollowContentFunction-自定义内容跟随策略,返回 true 则触底,false 则累计未读。回调参数含 reason / item / index / scrollState / unreadCount / autoScroll

事件

事件名参数说明
@load-more-top-向上滚到顶部达到阈值时触发,可在此请求加载历史消息。
@load-more-bottom-向下滚到底部达到阈值时触发,可在此请求加载更多消息。
@scroll-state-change(state: 'AT_BOTTOM' | 'SCROLLED_UP' | 'HAS_NEW_MESSAGES')滚动状态变化时触发。
@unread-count-change(count: number)未读计数变化时触发。

Ref 实例方法

方法 / 属性签名说明
scrollToTop(smooth?: boolean) => void滚动到顶部,smooth 控制是否平滑动画(默认由 smoothScroll 属性决定)。
scrollToBottom(smooth?: boolean) => void滚动到底部,同时清零未读计数并重置状态机。
scrollToBubble(index: number, smooth?: boolean) => void滚动到指定索引的消息。
loadMoreTopComplete() => void顶部数据加载完成后调用,组件自动修复滚动位置。
loadMoreBottomComplete() => void底部数据加载完成后调用。
currentScrollStateBubbleListScrollState当前滚动状态:AT_BOTTOM / SCROLLED_UP / HAS_NEW_MESSAGES
currentUnreadCountnumber当前未读消息数量。

插槽

插槽名上下文类型说明
#avatarBubbleListItemContext自定义气泡头像。
#headerBubbleListItemContext自定义气泡顶部区域。
#contentBubbleListItemContext自定义气泡内容区域。
#footerBubbleListItemContext自定义气泡底部区域。
#loadingBubbleListItemContext自定义气泡加载状态。
#backToBottomBubbleListBackButtonContext自定义回底按钮,上下文含 unreadCount / scrollState / label / autoScroll / virtualEnabled / scrollToBottom(smooth?)
#topStatusBubbleListBoundaryContext自定义顶部边界状态区,上下文含 status / position / scrollState / unreadCount / autoScroll
#bottomStatusBubbleListBoundaryContext自定义底部边界状态区,同 #topStatus
#itemBubbleListItemContext非气泡类型节点的自定义渲染,由 itemType 命中后触发。