更新记录
1.0.0(2026-08-11)
chat-list:高性能消息列表,支持自动滚动探底、触顶加载历史、用户 / 助手气泡差异化渲染、流式打字机指示。stream-markdown:流式 Markdown 与 LaTeX 公式渲染器,内置半包语法自动修复(未闭合的```代码块、$公式自动补全),支持代码高亮与一键复制。chat-input:交互输入框,支持自动换行、发送 / 停止状态切换、快捷 Prompt 推荐词,已适配底部安全区。streamDecoder核心库:手写 UTF-8 增量解码器(解决中文半包乱码)、标准 SSE 解析器、打字机缓冲队列,以及跨端统一的streamRequest(H5 用fetch、App / 微信小程序用onChunkReceived)。
平台兼容性
uni-app(3.8.2)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ | √ | √ | √ |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ |
流式对话与 Markdown 渲染组件(stream-chat-kit)
一套面向 uni-app(Vue 3 + TypeScript)的高扩展性、跨端兼容对话 UI 组件集,适用于构建在线客服、文档问答、知识助手等需要「流式输出 + Markdown / 公式渲染」的场景。
支持端:H5 / iOS App / Android App / 微信小程序。
特性
chat-list:高性能消息列表,支持自动滚动探底、触顶加载历史、用户 / 助手气泡差异化渲染、流式打字机指示。stream-markdown:流式 Markdown 与 LaTeX 公式渲染器,内置半包语法自动修复(未闭合的```代码块、$公式自动补全),支持代码高亮与一键复制。chat-input:交互输入框,支持自动换行、发送 / 停止状态切换、快捷 Prompt 推荐词,已适配底部安全区。streamDecoder核心库:手写 UTF-8 增量解码器(解决中文半包乱码)、标准 SSE 解析器、打字机缓冲队列,以及跨端统一的streamRequest(H5 用fetch、App / 微信小程序用onChunkReceived)。
目录结构
uni_modules/stream-chat-kit/
├── components/
│ ├── chat-list/chat-list.vue
│ ├── stream-markdown/stream-markdown.vue
│ └── chat-input/chat-input.vue
├── utils/
│ ├── streamDecoder.ts # 流解码与 SSE 兼容核心库
│ └── types.ts # 公共类型
├── utssdk/index.uts # 原生辅助模块(满足 uni_modules 发布规范)
└── package.json
依赖安装
组件通过动态引入使用 marked(Markdown 解析)与 katex(公式渲染),两个库均为可选依赖:未安装时组件自动降级为纯文本 / 原始公式展示,项目仍可正常运行。如需完整效果,请在项目根目录执行:
npm install marked katex
说明:KaTeX 的完整样式在 H5 / App 端自动注入;微信小程序端公式可正常渲染,但视觉样式受
rich-text限制,建议在页面全局引入katex/dist/katex.min.css以获得最佳效果。
快速上手
uni_modules 组件会被自动全局注册,无需手动 import。在页面中直接使用即可:
<template>
<view class="container">
<chat-list :messages="messages" :loading="loading" :theme="theme" @load-history="onHistory" />
<chat-input v-model="input" :loading="loading" :quick-prompts="prompts" @send="onSend" @stop="onStop" />
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { StreamBuffer } from '../../../uni_modules/stream-chat-kit/utils/streamDecoder'
import type { ChatMessage } from '../../../uni_modules/stream-chat-kit/utils/types'
const messages = ref<ChatMessage[]>([])
const input = ref('')
const loading = ref(false)
const theme = ref<'light' | 'dark'>('light')
const prompts = ['介绍一下 Vue 3', '写一段快速排序']
function onSend(text: string) {
const t = text.trim()
if (!t || loading.value) return
messages.value.push({ id: Date.now() + '', role: 'user', content: t, status: 'done' })
const aiId = Date.now() + '-ai'
messages.value.push({ id: aiId, role: 'assistant', content: '', status: 'streaming' })
loading.value = true
// 用打字机缓冲队列把高频字符节流后写入消息
const buffer = new StreamBuffer(20, (chunk) => {
const msg = messages.value.find((m) => m.id === aiId)
if (msg) msg.content += chunk
})
// 这里以本地字符串模拟流式,真实场景替换为 streamRequest 的 onMessage
let i = 0
const full = '这是**流式**回复示例,支持 `代码` 与公式 $a^2+b^2=c^2$。'
const timer = setInterval(() => {
if (i >= full.length) {
clearInterval(timer)
buffer.flush()
const m = messages.value.find((x) => x.id === aiId)
if (m) m.status = 'done'
loading.value = false
return
}
buffer.push(full.slice(i, i + 3))
i += 3
}, 30)
}
function onStop() { loading.value = false }
function onHistory() { /* 在此向前追加历史消息 */ }
</script>
对接真实 SSE 后端
import { streamRequest } from '../../../uni_modules/stream-chat-kit/utils/streamDecoder'
const handle = streamRequest({
url: 'https://your-api.com/v1/chat/stream',
method: 'POST',
header: { Authorization: 'Bearer <token>' },
data: { message: text },
onMessage: (data) => {
const json = JSON.parse(data)
const delta = json.choices?.[0]?.delta?.content || ''
const msg = messages.value.find((m) => m.id === aiId)
if (msg) msg.content += delta // stream-markdown 会自动修复半包语法
},
onDone: () => { /* 标记完成 */ },
onError: (e) => { /* 错误处理 */ }
})
// 中断:handle.abort()
组件 API
chat-list
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| messages | ChatMessage[] |
[] |
消息列表 |
| loading | boolean |
false |
全局加载态,最后一条助手消息等待首字时显示 |
| theme | 'light' \| 'dark' |
light |
主题 |
| userAvatar | string |
— | 用户头像 URL |
| botAvatar | string |
— | 助手头像 URL |
| unread | number |
0 |
“回到底部”按钮角标数 |
事件:
| 事件 | 参数 | 说明 |
|---|---|---|
| load-history | — | 列表滚动到顶部时触发,用于加载更早的消息 |
stream-markdown
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| content | string |
'' |
流式内容(可未闭合) |
| theme | 'light' \| 'dark' |
light |
主题(影响代码块配色) |
特性:自动修复未闭合代码块 / 公式、代码高亮 + 一键复制、KaTeX 公式渲染(降级为原始公式文本)。
chat-input
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| modelValue | string |
'' |
v-model 输入内容 |
| loading | boolean |
false |
请求中(按钮变为“停止”) |
| theme | 'light' \| 'dark' |
light |
主题 |
| placeholder | string |
输入消息… |
占位文案 |
| quickPrompts | (string \| QuickPrompt)[] |
[] |
快捷推荐词 |
| showQuick | boolean |
true |
是否展示快捷词 |
| autoSend | boolean |
true |
点击快捷词后是否自动发送 |
事件:
| 事件 | 参数 | 说明 |
|---|---|---|
| update:modelValue | string |
输入内容变化 |
| send | string |
点击发送或回车 |
| stop | — | 请求中点“停止” |
| quick | string |
点击快捷词 |
公共类型
type ChatRole = 'user' | 'assistant' | 'system'
type ChatMessageStatus = 'pending' | 'streaming' | 'done' | 'error'
interface ChatMessage {
id: string
role: ChatRole
content: string
status?: ChatMessageStatus
createdAt?: number
extra?: Record<string, any>
}
平台兼容说明
| 能力 | H5 | App | 微信小程序 |
|---|---|---|---|
| 流式请求 | fetch Reader |
uni.request chunked |
uni.request onChunkReceived |
| 中文半包解码 | ✅ | ✅ | ✅ |
| Markdown / 代码高亮 | ✅ | ✅ | ✅ |
| KaTeX 公式(带样式) | ✅ | ✅ | △(需全局引 CSS) |
本地运行 Demo
- 用 HBuilder X 打开本仓库根目录(含
manifest.json的项目根)。 - 在项目根目录执行
npm install marked katex安装可选依赖。 - 点 HBuilder X 顶部「运行」→ 选择 H5 / 微信小程序 / App 基座即可预览。
- Demo 页位于
src/pages/index/index.vue,使用本地模拟流式输出,无需后端即可体验。
许可
MIT

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 8
赞赏 0
下载 12639940
赞赏 1950
赞赏
京公网安备:11010802035340号