一文吃透TinyRobot Bubble:从基础组件搭建完整 AI 消息渲染体系
在前端 AI 应用中,消息气泡(Bubble)是最核心的 UI 元素------它承载了从纯文本到 Markdown、从图片到工具调用的全部信息渲染。TinyRobot 的 Bubble 组件采用独特的"渲染器架构",提供了从基础气泡到复杂多模态消息的完整解决方案。
本文将从 Bubble 的基础用法入手,逐步深入到渲染器体系、状态管理、内容解析,带你搭建一套完整的 AI 消息渲染体系。
一、Bubble 基础:最小可用的消息气泡
1.1 最简示例
Bubble 的核心就是 content 属性------给它内容,它就能渲染:
vue
<template>
<tr-bubble
content="TinyRobot 是一个专为 AI 应用设计的 Vue 3 组件库。"
style="--tr-bubble-box-bg: var(--tr-color-primary-light)"
/>
</template>
<script setup lang="ts">
import { TrBubble } from '@opentiny/tiny-robot'
</script>
CSS 变量让你零成本自定义样式------背景色、字号、圆角、阴影等全部可控。
1.2 头像与位置
通过 avatar 和 placement 控制气泡的视觉归属:
vue
<template>
<tr-bubble content="AI 回复" :avatar="aiAvatar" placement="start" />
<tr-bubble content="用户消息" :avatar="userAvatar" placement="end" />
</template>
<script setup lang="ts">
import { TrBubble } from '@opentiny/tiny-robot'
import { IconAi, IconUser } from '@opentiny/tiny-robot-svgs'
import { h } from 'vue'
const aiAvatar = h(IconAi, { style: { fontSize: '32px' } })
const userAvatar = h(IconUser, { style: { fontSize: '32px' } })
</script>
placement: 'start'--- 气泡靠左(AI 侧)placement: 'end'--- 气泡靠右(用户侧)
1.3 气泡形状
shape 属性支持三种形状:
| 值 | 效果 | 适用场景 |
|---|---|---|
'corner'(默认) |
对话泡泡形状,单侧有尖角 | 经典对话界面 |
'rounded' |
四角等圆角 | 现代 UI 风格 |
'none' |
无特殊圆角处理 | 自定义布局 |
vue
<tr-bubble content="消息内容" shape="rounded" />
1.4 加载状态
loading 属性让气泡在 AI 思考时展示等待状态:
vue
<tr-bubble :loading="true" />
二、内容渲染:从纯文本到多模态
2.1 Markdown 渲染
AI 回复中 Markdown 是标配。Bubble 内置了 Markdown 渲染器,只需安装依赖并配置:
bash
pnpm add markdown-it dompurify
vue
<template>
<tr-bubble
:content="mdContent"
:fallback-content-renderer="BubbleRenderers.Markdown"
/>
</template>
<script setup lang="ts">
import { TrBubble, BubbleRenderers } from '@opentiny/tiny-robot'
const mdContent = '## 标题\n\n这是 **加粗** 和 `代码` 的混合内容'
</script>
注意:BubbleList 中使用 Markdown 渲染器,需要用 BubbleProvider 包裹。
2.2 流式文本
Bubble 的 content 属性是响应式的------动态修改它就能实现流式效果:
vue
<template>
<tr-bubble :content="streamContent" :avatar="aiAvatar" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
const streamContent = ref('')
const startStream = async () => {
streamContent.value = ''
for (const char of '这是流式输出的文本内容。') {
streamContent.value += char
await new Promise(resolve => setTimeout(resolve, 100))
}
}
</script>
搭配 useMessage 的 responseProvider,真正的 SSE 流式输出只需几行代码。
2.3 图片渲染
当 content 为数组且包含 type: 'image_url' 时,自动使用 Image 渲染器:
typescript
const imageMessage = [
{ type: 'text', text: '这是一张图片:' },
{ type: 'image_url', image_url: { url: 'https://example.com/photo.jpg' } },
]
通过 contentRenderMode 控制图文渲染方式:
'single'(默认):文本和图片在同一个 box 中'split':每个内容项单独一个 box
vue
<tr-bubble :content="imageMessage" content-render-mode="split" />
2.4 内容渲染模式详解
contentRenderMode 是理解 Bubble 渲染的关键概念:
rust
content = "纯文本" → 单个 box
content = [{type:'text'...}] → single模式:1个box / split模式:N个box
content = [{type:'text'...}, {type:'image_url'...}]
→ single模式:1个box(图文混合)
→ split模式:2个box(文字+图片各自独立)
三、插槽系统:定制气泡的每一个角落
Bubble 提供四个插槽,让你精准控制气泡结构:
| 插槽 | 位置 | 用途 |
|---|---|---|
prefix |
气泡内容前 | 添加标签、时间戳等 |
suffix |
气泡内容后 | 添加操作按钮等 |
content-footer |
内容底部 | 添加引用来源等 |
after |
气泡外部 | 添加反馈、评分等 |
vue
<tr-bubble content="AI 回复">
<template #prefix>
<span class="label">AI助手</span>
</template>
<template #content-footer>
<tr-feedback :actions="feedbackActions" />
</template>
<template #after>
<span class="timestamp">刚刚</span>
</template>
</tr-bubble>
四、完整 AI 对话渲染体系搭建
把上述能力组合起来,一个完整的 AI 对话界面就成型了:
vue
<template>
<tr-bubble-provider :fallback-content-renderer="BubbleRenderers.Markdown">
<tr-bubble-list
:messages="messages"
:role-configs="roleConfigs"
:auto-scroll="true"
/>
<tr-sender
v-model="inputText"
:loading="isProcessing"
@submit="handleSend"
@cancel="handleCancel"
/>
</tr-bubble-provider>
</template>
<script setup lang="ts">
import { ref, computed, h } from 'vue'
import { TrBubbleList, TrBubbleProvider, TrSender, BubbleRenderers } from '@opentiny/tiny-robot'
import { useMessage, sseStreamToGenerator } from '@opentiny/tiny-robot-kit'
import { IconAi, IconUser } from '@opentiny/tiny-robot-svgs'
const inputText = ref('')
const roleConfigs = {
ai: { placement: 'start', avatar: h(IconAi, { style: { fontSize: '32px' } }) },
user: { placement: 'end', avatar: h(IconUser, { style: { fontSize: '32px' } }) },
}
const { messages, sendMessage, requestState, abortRequest } = useMessage({
responseProvider: async (body, signal) => {
const res = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
signal,
})
return sseStreamToGenerator(res, { signal })
},
})
const isProcessing = computed(() => requestState.value === 'processing')
const handleSend = (text: string) => { inputText.value = ''; sendMessage(text) }
const handleCancel = () => abortRequest()
</script>
关键点:
- BubbleProvider 包裹 BubbleList,统一配置 Markdown 渲染器
- BubbleList 的
roleConfigs批量配置角色头像和位置 - useMessage 提供消息数据和流式引擎
- TrSender 负责输入和发送
这就是 TinyRobot 的"组件+Kit"双层架构带来的极致简洁------UI 层和数据层各司其职,组合即用。
五、CSS 变量速查
Bubble 提供了丰富的 CSS 变量用于样式定制:
气泡容器:
--tr-bubble-box-bg--- 背景色--tr-bubble-box-padding--- 内边距--tr-bubble-box-border-radius--- 圆角--tr-bubble-max-width--- 最大宽度
文本:
--tr-bubble-text-color--- 文字颜色--tr-bubble-text-font-size--- 字号--tr-bubble-text-line-height--- 行高
图片:
--tr-bubble-image-max-width/--tr-bubble-image-max-height--- 图片尺寸限制
工具调用:
--tr-bubble-tool-call-bg--- 工具卡片背景色--tr-bubble-tool-key-color--- JSON key 颜色
按角色定制样式也很方便------BubbleList 会为每个组添加 data-role 属性:
css
[data-role='user'] {
--tr-bubble-box-bg: var(--tr-color-primary-light);
}
[data-role='ai'] {
--tr-bubble-box-bg: #f5f5f5;
}
六、总结
从最小可用的 tr-bubble 到完整的对话渲染体系,TinyRobot Bubble 的设计思路清晰:
- 单一职责:一个 Bubble 只渲染一条消息
- 渲染器架构:内容渲染与容器渲染完全可插拔
- 响应式驱动:content 变化即更新,天然适配流式场景
- CSS 变量定制:样式不侵入逻辑,零成本适配品牌风格
掌握了 Bubble 的基础组件能力,下一篇文章我们将深入 BubbleList,探索多轮对话、消息分组与滚动体验优化。
TinyRobot 官网 :https://opentiny/tiny-robot GitHub 仓库 :github.com/opentiny/ti...