BubbleList 气泡列表 🍅
📌 注意
1.1.6 版本
继承打字器 雾化 效果。新增 滚动底部按钮,仿 豆包
🔥。新增 鼠标悬停展示滚动条,增强交互体验。请及时更新尝试
🐵 此温馨提示更新时间:2025-04-13
💔 危险
1.0.81 版本
,以及更早版本。BubbleList
组件的自动滚动逻辑,会和内置的打字器组件结合使用,可能会导致在自定义 content
插槽时, 自动滚动
失效`。且存在一定的性能问题。
上述问题在新版本中已修复,请及时升级至最新版本,以获得更好的体验。
此警告更新时间:2025-04-06
💡 提示
另: 新版本的自动滚动,在 list
长度变化时,自动滚动。但是 向上滚动滚动条后,需要手动调用 scrollToBottom
方法,以再次实现自动滚动。或者 滚动条滚动到底部后,会重新触发自动滚动。
和原来逻辑一样, 升级无需任何心理负担。
介绍
BubbleList
依赖于 Bubble
组件,用于展示一组对话气泡列表。该组件支持设置 列表最大高度
,具备 自动滚动
功能。同时,它还提供了多种 控制滚动
的方法,使用者
可以轻松调用,性能强大,无需任何开发心理负担。
代码演示
基本使用



预设样式的气泡列表,通过一个消息简单的 Array
,可以快速创建一个聊天记录。
我们所有的消息操作,只需要维护这个数组就行了,包括 流式消息
的设置。这里没有使用接口流式操作。在下面有
你还可以通过属性 max-height
来控制列表的最大高度。
<script setup lang="ts">
import type { BubbleListItemProps, BubbleListProps } from 'vue-element-plus-x/types/BubbleList'
type listType = BubbleListItemProps & {
key: number
role: 'user' | 'ai'
}
// 示例调用
const list: BubbleListProps<listType>['list'] = generateFakeItems(5)
function generateFakeItems(count: number): listType[] {
const messages: listType[] = []
for (let i = 0; i < count; i++) {
const role = i % 2 === 0 ? 'ai' : 'user'
const placement = role === 'ai' ? 'start' : 'end'
const key = i + 1
const content = role === 'ai'
? '💖 感谢使用 Element Plus X ! 你的支持,是我们开源的最强动力 ~'.repeat(5)
: `哈哈哈,让我试试`
const loading = false
const shape = 'corner'
const variant = role === 'ai' ? 'filled' : 'outlined'
const isMarkdown = false
const typing = role === 'ai' ? i === count - 1 : false
const avatar = role === 'ai'
? 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png'
: 'https://avatars.githubusercontent.com/u/76239030?v=4'
messages.push({
key, // 唯一标识
role, // user | ai 自行更据模型定义
placement, // start | end 气泡位置
content, // 消息内容 流式接受的时候,只需要改这个值即可
loading, // 当前气泡的加载状态
shape, // 气泡的形状
variant, // 气泡的样式
isMarkdown, // 是否渲染为 markdown
typing, // 是否开启打字器效果 该属性不会和流式接受冲突
isFog: role === 'ai', // 是否开启打字雾化效果,该效果 v1.1.6 新增,且在 typing 为 true 时生效,该效果会覆盖 typing 的 suffix 属性
avatar,
avatarSize: '24px', // 头像占位大小
avatarGap: '12px', // 头像与气泡之间的距离
})
}
return messages
}
</script>
<template>
<BubbleList :list="list" max-height="350px" />
</template>
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
自定义列表



🍋 通过 #avatar
、#header
、#content
、#loading
、#footer
插槽,可以更灵活的控制气泡列表的渲染
<script setup lang="ts">
import type { BubbleListItemProps, BubbleListProps } from 'vue-element-plus-x/types/BubbleList'
import { DocumentCopy, Refresh, Search, Star } from '@element-plus/icons-vue'
type listType = BubbleListItemProps & {
key: number
role: 'user' | 'ai'
}
// 示例调用
const bubbleItems = ref<BubbleListProps<listType>['list']>(generateFakeItems(5))
const avatar = ref('https://avatars.githubusercontent.com/u/76239030?v=4')
const avartAi = ref('https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png')
const switchValue = ref(false)
const loading = ref(false)
function generateFakeItems(count: number): listType[] {
const messages: listType[] = []
for (let i = 0; i < count; i++) {
const role = i % 2 === 0 ? 'ai' : 'user'
const placement = role === 'ai' ? 'start' : 'end'
const key = i + 1
messages.push({
key,
role,
placement,
noStyle: true, // 如果你不想用默认的气泡样式
})
}
return messages
}
// 设置某个 item 的 loading
function setLoading(loading: boolean) {
bubbleItems.value[bubbleItems.value.length - 1].loading = loading
bubbleItems.value[bubbleItems.value.length - 2].loading = loading
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<div style="display: flex; gap: 12px;">
<span>动态设置内容 <el-switch v-model="switchValue" /></span>
<span>自定义 loading <el-switch v-model="loading" @change="(value: any) => setLoading(value as boolean)" /></span>
</div>
<BubbleList :list="bubbleItems" max-height="350px">
<!-- 自定义头像 -->
<template #avatar="{ item }">
<div class="avatar-wrapper">
<img :src="item.role === 'ai' ? avartAi : avatar" alt="avatar">
</div>
</template>
<!-- 自定义头部 -->
<template #header="{ item }">
<div class="header-wrapper">
<div class="header-name">
{{ item.role === 'ai' ? 'Element Plus X 🍧' : '🧁 用户' }}
</div>
</div>
</template>
<!-- 自定义气泡内容 -->
<template #content="{ item }">
<div class="content-wrapper">
<div class="content-text">
{{ item.role === 'ai' ? `${switchValue ? `#ai-${item.key}:` : ''} 💖 感谢使用 Element Plus X ! 你的支持,是我们开源的最强动力 ~` : `${switchValue ? `#user-${item.key}:` : ''}哈哈哈,让我试试` }}
</div>
</div>
</template>
<!-- 自定义底部 -->
<template #footer="{ item }">
<div class="footer-wrapper">
<div class="footer-container">
<el-button type="info" :icon="Refresh" size="small" circle />
<el-button type="success" :icon="Search" size="small" circle />
<el-button type="warning" :icon="Star" size="small" circle />
<el-button color="#626aef" :icon="DocumentCopy" size="small" circle />
</div>
<div class="footer-time">
{{ item.role === 'ai' ? '下午 2:32' : '下午 2:33' }}
</div>
</div>
</template>
<!-- 自定义 loading -->
<template #loading="{ item }">
<div class="loading-container">
<span>#{{ item.role }}-{{ item.key }}:</span>
<span>我</span>
<span>是</span>
<span>自</span>
<span>定</span>
<span>义</span>
<span>加</span>
<span>载</span>
<span>内</span>
<span>容</span>
<span>哦</span>
<span>~</span>
</div>
</template>
</BubbleList>
</div>
</template>
<style scoped lang="less">
.avatar-wrapper {
width: 40px;
height: 40px;
img {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.header-wrapper {
.header-name {
font-size: 14px;
color: #979797;
}
}
.content-wrapper {
.content-text {
font-size: 14px;
color: #333;
padding: 12px;
background: linear-gradient(to right, #fdfcfb 0%, #ffd1ab 100%);
border-radius: 15px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
}
.footer-wrapper {
display: flex;
align-items: center;
gap: 10px;
.footer-time {
font-size: 12px;
margin-top: 3px;
}
}
.footer-container {
:deep(.el-button+.el-button) {
margin-left: 8px;
}
}
.loading-container {
font-size: 14px;
color: #333;
padding: 12px;
background: linear-gradient(to right, #fdfcfb 0%, #ffd1ab 100%);
border-radius: 15px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.loading-container span {
display: inline-block;
margin-left: 8px;
}
@keyframes bounce {
0%, 100% {
transform: translateY(5px);
}
50% {
transform: translateY(-5px);
}
}
.loading-container span:nth-child(4n) {
animation: bounce 1.2s ease infinite;
}
.loading-container span:nth-child(4n+1) {
animation: bounce 1.2s ease infinite;
animation-delay: .3s;
}
.loading-container span:nth-child(4n+2) {
animation: bounce 1.2s ease infinite;
animation-delay: .6s;
}
.loading-container span:nth-child(4n+3) {
animation: bounce 1.2s ease infinite;
animation-delay: .9s;
}
</style>
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
自动滚动、指定滚动位置

🍑 你可以轻松使用 bubbleListRef
组件实例方法,控制 滚动到指定索引。
🍒 组件实例方法
scrollToTop()
:滚动到顶部scrollToBottom()
:滚动到底部scrollToBubble(index: number)
:滚动到指定索引
<script setup lang="ts">
import type { BubbleListItemProps, BubbleListProps } from 'vue-element-plus-x/types/BubbleList'
import type { TypewriterProps } from 'vue-element-plus-x/types/Typewriter'
type listType = BubbleListItemProps & {
key: number
role: 'user' | 'ai'
}
// 示例调用
const bubbleItems = ref<BubbleListProps<listType>['list']>(generateFakeItems(2))
function generateFakeItems(count: number): listType[] {
const messages: listType[] = []
for (let i = 0; i < count; i++) {
const role = i % 2 === 0 ? 'ai' : 'user'
const placement = role === 'ai' ? 'start' : 'end'
const key = i + 1
const content = role === 'ai'
? '💖 感谢使用 Element Plus X ! 你的支持,是我们开源的最强动力 ~'
: `哈哈哈,让我试试`
const loading = false
const shape = 'corner'
const variant = role === 'ai' ? 'filled' : 'outlined'
const isMarkdown = false
const typing = false
const avatar = role === 'ai'
? 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png'
: 'https://avatars.githubusercontent.com/u/76239030?v=4'
messages.push({
key,
role,
placement,
content,
loading,
shape,
variant,
isMarkdown,
typing,
avatar,
avatarSize: '32px',
})
}
return messages
}
const bubbleListRef = ref()
const num = ref(0)
function addMessage() {
const i = bubbleItems.value.length
const isUser = !!(i % 2)
const content = isUser
? '哈哈哈,让我试试'
: '💖 感谢使用 Element Plus X ! 你的支持,是我们开源的最强动力 ~'.repeat(5)
const shape = 'corner'
const variant = !isUser ? 'filled' : 'outlined'
const placement = isUser ? 'end' : 'start'
const typing: TypewriterProps['typing'] = isUser ? false : { step: 5, suffix: '🍆', interval: 35 }
const avatar = isUser
? 'https://avatars.githubusercontent.com/u/76239030?v=4'
: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png'
const obj = {
key: i,
role: isUser ? 'user' : 'ai',
content,
placement,
typing,
avatar,
shape,
variant,
avatarSize: '32px',
isFog: !isUser,
}
bubbleItems.value.push(obj as listType)
// 每次添加 调用 滚动到底部 触发 自动滚动
scrollBottom()
}
function clearMessage() {
bubbleItems.value = []
}
function scrollToTop() {
bubbleListRef.value.scrollToTop()
}
function scrollBottom() {
bubbleListRef.value.scrollToBottom()
}
function scrollToBubble() {
bubbleListRef.value.scrollToBubble(num.value)
}
onMounted(() => {
setTimeout(() => {
bubbleItems.value.map((item) => {
item.loading = false
return item
})
}, 3000)
})
</script>
<template>
<div class="component-container">
<div class="top-wrap">
<div class="btn-list">
<el-button type="primary" plain @click="addMessage">
添加对话
</el-button>
<el-button type="danger" plain @click="clearMessage">
清空对话列表
</el-button>
<el-button type="primary" plain @click="scrollToTop">
滚动到顶部
</el-button>
<el-button type="primary" plain @click="scrollBottom">
滚动到底部
</el-button>
</div>
<div class="btn-list">
<el-input-number v-model="num" :min="0" :max="10" controls-position="right" />
<el-button type="primary" plain @click="scrollToBubble">
滚动第{{ num }}个气泡框
</el-button>
</div>
</div>
<div class="component-1">
<BubbleList ref="bubbleListRef" :list="bubbleItems" max-height="350px" />
</div>
</div>
</template>
<style scoped lang="less">
.component-container {
padding: 12px;
.btn-list {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.top-wrap {
display: flex;
flex-direction: column;
gap: 12px;
margin-bottom: 24px;
}
}
</style>
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
返回顶部按钮






- 内置回到底部按钮,仿
豆包
。 - 鼠标悬停时,会出现滚动条
- 和内置自动滚动不冲突,请放心使用
💌 消息
滚动条控制属性
alwaysShowScrollbar
属性控制是否一直显示滚动条,默认为false
。
底部按钮定制化属性
- 你可以通过
backButtonThreshold
属性来设置回到底部按钮的阈值,默认为80
,即当滚动条滚动到距离底部80px
时,才会出现回到底部按钮。 showBackButton
属性控制是否显示回到底部按钮,默认为true
。btnLoading
属性控制是否显示加载中的状态,默认为true
。btnColor
属性控制回到底部按钮的颜色,默认为#409EFF
。backButtonPosition
属性控制回到底部按钮的位置,默认为{ bottom: '20px', left: 'calc(50% - 19px)' }
可以用%
来控制,如{ bottom: '10%', left: 'calc(50% - 19px)' }
。btnIconSize
属性控制回到底部按钮的图标大小,默认为24
。
<script setup lang="ts">
import type { BubbleListItemProps, BubbleListProps } from 'vue-element-plus-x/types/BubbleList'
type listType = BubbleListItemProps & {
key: number
role: 'user' | 'ai'
}
// 示例调用
const list: BubbleListProps<listType>['list'] = generateFakeItems(12)
const alwaysShowScrollbar = ref(false)
const btnLoading = ref(true)
const bottomValue = ref(10)
const leftValue = ref(85)
const backButtonPosition = computed(() => {
return {
bottom: `${bottomValue.value}%`,
left: `${leftValue.value}%`,
}
})
const btnColor = ref('#2D38FF')
const btnSize = ref(40)
function generateFakeItems(count: number): listType[] {
const messages: listType[] = []
for (let i = 0; i < count; i++) {
const role = i % 2 === 0 ? 'ai' : 'user'
const placement = role === 'ai' ? 'start' : 'end'
const key = i + 1
const content = role === 'ai'
? '💖 感谢使用 Element Plus X ! 你的支持,是我们开源的最强动力 ~'.repeat(8)
: `哈哈哈,让我试试`
const loading = false
const shape = 'corner'
const variant = role === 'ai' ? 'filled' : 'outlined'
const isMarkdown = false
const typing = role === 'ai' ? i === count - 1 : false
const avatar = role === 'ai'
? 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png'
: 'https://avatars.githubusercontent.com/u/76239030?v=4'
messages.push({
key, // 唯一标识
role, // user | ai 自行更据模型定义
placement, // start | end 气泡位置
content, // 消息内容 流式接受的时候,只需要改这个值即可,这里暂时没有用到流式数据
loading, // 当前气泡的加载状态
shape, // 气泡的形状
variant, // 气泡的样式
isMarkdown, // 是否渲染为 markdown
typing, // 是否开启打字器效果 该属性不会和流式接受冲突
isFog: role === 'ai', // 是否开启打字雾化效果,该效果 v1.1.6 新增,且在 typing 为 true 时生效,该效果会覆盖 typing 的 suffix 属性
avatar,
avatarSize: '24px', // 头像占位大小
avatarGap: '12px', // 头像与气泡之间的距离
})
}
return messages
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 24px;">
<div style="display: flex; gap: 5px; border: 1px solid gray; border-radius: 12px; padding: 8px; flex-direction: column;">
<span>滚动条显示:<el-switch v-model="alwaysShowScrollbar" inactive-text="鼠标悬停展示" active-text="一直展示" /></span>
<span>底部按钮加载状态:<el-switch v-model="btnLoading" inactive-text="false" active-text="true" /></span>
<span>底部按钮颜色: <el-color-picker v-model="btnColor" /></span>
<span>底部按钮位</span>
<span>距离底部:<el-slider v-model="bottomValue" /></span>
<span>距离左边:<el-slider v-model="leftValue" /></span>
<span>底部按钮尺寸:<el-slider v-model="btnSize" /></span>
</div>
<BubbleList :list="list" max-height="350px" :always-show-scrollbar="alwaysShowScrollbar" :btn-color="btnColor" :btn-loading="btnLoading" :back-button-position="backButtonPosition" :btn-icon-size="btnSize" />
</div>
</template>
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
滚动完成事件
📌 注意
极特殊情况才用的到,在流式输出中不适用,会快速触发打字结束事件。
🍉该属性使用场景很少,请酌情使用,更细致的控制你的气泡在列表中的 完成事件
。
你可以通过 @complete
事件,触发列表,每一个打字中的 Bubble
气泡组件的 完成打字
的回调事件。
@complete
返回两个参数,instance
是 打字器组件实例 和 index
是 BubbleListItem
的索引。
💡 提示
@complete
事件仅会触发typing
属性为true
的Bubble 组件
回调事件。- 如果你给列表配置了多个气泡的
typing
属性,列表默认只处理最后一个typing
为true
的气泡的@complete
事件。
💌 消息
- 如果你需要处理多个
typing
为true
的气泡完成回调事件,你可以通过triggerIndices
属性来指定需要处理的气泡的索引。它是一个'only-last' | 'all' | number[]
类型。 - 默认为
'only-last'
,只执行 最后一个typing
为true
的气泡的@complete
事件。 'all'
表示执行所有typing
为true
的气泡的@complete
事件。@complete
将会被执行多次。number[]
设置你想要监听的BubbleListItem
的索引。组件会自动过滤无效的索引
,并输出console.warn
<script setup lang="ts">
import type { BubbleListItemProps, BubbleListProps } from 'vue-element-plus-x/types/BubbleList'
import type { TypewriterInstance } from 'vue-element-plus-x/types/Typewriter'
type listType = BubbleListItemProps & {
key: number
role: 'user' | 'ai'
}
// 示例调用
const list = ref<BubbleListProps<listType>['list']>(generateFakeItems(0))
function generateFakeItems(count: number): listType[] {
const messages: listType[] = []
for (let i = 0; i < count; i++) {
const role = i % 2 === 0 ? 'ai' : 'user'
const placement = role === 'ai' ? 'start' : 'end'
const key = i + 1
const content = role === 'ai'
? '💖 感谢使用 Element Plus X ! 你的支持,是我们开源的最强动力 ~'
: `哈哈哈,让我试试`
const loading = false
const shape = 'corner'
const variant = role === 'ai' ? 'filled' : 'outlined'
const isMarkdown = false
const typing = role === 'ai'
const avatar = role === 'ai'
? 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png'
: 'https://avatars.githubusercontent.com/u/76239030?v=4'
messages.push({
key,
role,
placement,
content,
loading,
shape,
variant,
isMarkdown,
typing,
avatar,
avatarSize: '24px',
})
}
return messages
}
function onComplete(instance: TypewriterInstance, index: number) {
console.log('@complete', instance, index)
}
const triggerIndices = ref<BubbleListProps['triggerIndices']>('only-last')
function changeTriggerIndices(type: 'only-last' | 'all' | number[]) {
triggerIndices.value = type
// 重新生成列表数据
list.value = []
nextTick(() => {
list.value = generateFakeItems(7)
})
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<div style="display: flex; align-items: center;">
<span style="margin-right: 12px;">trigger-indices: </span>
<el-button style="width: fit-content;" @click="changeTriggerIndices('only-last')">
only-last
</el-button>
<el-button style="width: fit-content;" type="primary" @click="changeTriggerIndices('all')">
all
</el-button>
<el-button style="width: fit-content;" type="success" @click="changeTriggerIndices([1, 2, 3])">
[1, 2, 3]
</el-button>
</div>
<BubbleList :list="list" max-height="350px" :trigger-indices="triggerIndices" @complete="onComplete" />
</div>
</template>
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
属性
属性名 | 类型 | 是否必填 | 默认值 | 说明 |
---|---|---|---|---|
list | Array | 是 | 无 | 包含气泡信息的数组,每个元素为一个对象,包含 content 、placement 、loading 、shape 、variant 、isMarkdown 、typing 等 Bubble 属性,用于配置每个气泡的显示内容和样式。 |
maxHeight | String | 否 | '500px' | 气泡列表容器的最大高度,超过该高度会出现垂直滚动条。 |
alwaysShowScrollbar | Boolean | 否 | false | 是否一直显示滚动条,默认为 false 。 |
backButtonThreshold | Number | 否 | 80 | 滚动条显示阈值,当滚动条距离底部小于该值时,会显示滚动条。 |
showBackButton | Boolean | 否 | true | 是否显示返回顶部按钮,默认为 true 。 |
backButtonPosition | { bottom: '20px', left: 'calc(50% - 19px)' } | 否 | { bottom: '20px', left: 'calc(50% - 19px)' } | 返回顶部按钮的位置, 默认底部居中展示。 |
btnLoading | Boolean | 否 | true | 是否开启返回顶部按钮 loading 状态,默认为 true 。 |
btnColor | String | 否 | '#409EFF' | 返回顶部按钮的颜色,默认为 '#409EFF' 。 |
btnIconSize | Number | 否 | 24 | 返回顶部按钮的图标大小,默认为 24px。 |
triggerIndices | 'only-last' | 'all' | number[] | 否 | 'only-last' | 触发滚动完成事件的气泡 索引数组 ,默认为 'only-last' 。 |
事件
事件名 | 参数 | 类型 | 描述 |
---|---|---|---|
@complete | (instance, index) | Function | 当某个气泡的打字效果完成时触发的事件。 |
Ref 实例方法
属性名 | 类型 | 描述 |
---|---|---|
scrollToTop | Function | 滚动到顶部。 |
scrollToBottom | Function | 滚动到底部。 |
scrollToBubble | Function | 滚动到指定气泡索引位置。 |
插槽
插槽名 | 参数 | 类型 | 描述 |
---|---|---|---|
#avatar | - | Slot | 自定义头像展示内容 |
#header | - | Slot | 自定义气泡顶部展示内容 |
#content | - | Slot | 自定义气泡展示内容 |
#loading | - | Slot | 自定义气泡加载状态展示内容 |
#footer | - | Slot | 自定义气泡加载状态展示内容 |
功能特性
- 智能滚动 - 自动跟踪最新消息位置
- 深度定制 - 完整的气泡组件插槽透传
- 多种滚动方式 - 滚动到顶部、底部、指定位置
- 打字效果 - 支持打字效果
- 多种样式 - 支持多种样式,如圆形、方形等