TinyRobot Sender:构建卓越的AI聊天输入体验
复制代码
输入组件为何如此关键
在AI聊天应用中,输入框是用户与人工智能之间最核心的交互界面。一个优秀的输入组件,不仅仅是文本的“容器”,更是用户意图与AI能力之间的桥梁。无论底层模型多么强大,如果用户无法精准、高效地表达自己的想法,整个AI体验都会大打折扣。

传统的 或 已经难以满足现代AI应用的复杂需求。用户需要:
- 结构化输入:通过模板快速构建复杂的Prompt
- 智能联想:输入时自动提示相关话题或产品
- @提及:快速引用预设角色或上下文
- 语音输入:解放双手,自然表达
- 文件上传:将图片、文档等作为对话上下文
TinyRobot Sender 正是为此而生 —— 它是一个高度可组合、可扩展的AI聊天输入组件,基于Tiptap富文本编辑器构建,提供企业级的输入体验。
快速上手
1. 基本用法:模式切换
Sender 支持单行 (single) 和多行 (multiple) 两种输入模式。单行模式下,内容超出宽度时会自动切换为多行,无需用户手动调整。
复制代码
核心 Props 说明:
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
modelValue / v-model | 输入框内容绑定 | string | '' |
mode | 输入模式 | 'single' | 'multiple' | 'single' |
disabled | 是否禁用 | boolean | false |
loading | 加载状态(显示停止按钮) | boolean | false |
maxLength | 最大输入长度 | number | Infinity |
showWordLimit | 显示字数统计 | boolean | false |
size | 组件尺寸 | 'normal' | 'small' | 'normal' |
扩展架构:可插拔的功能增强
Sender 的核心设计理念是可插拔的扩展架构。通过 extensions prop,你可以按需组合 Template、Mention、Suggestion 等功能扩展,每个扩展互相独立、自由组合。
复制代码// 扩展就是普通的数组元素
const extensions = [
TrSender.template(templateData),
TrSender.mention(mentionItems),
TrSender.suggestion(suggestionItems, { filterFn: customFilter })
]// 通过 props 传入
<TrSender :extensions="extensions" />
提供两种集成方式:
- 便捷函数(推荐):
TrSender.template()、TrSender.mention()、TrSender.suggestion(),用于简单场景 - 标准配置:
TrSender.Mention.configure({...}),用于复杂配置(如自定义 onSelect 回调、filterFn 等)
2. Template 扩展:结构化 Prompt 模板
Template 扩展让用户通过预设模板快速填写结构化 Prompt。支持 text(固定文本)、block(可编辑字段)、select(下拉选择器)三种节点类型。
复制代码
Template 通过响应式 ref 机制,当 templateData.value 发生变化时,编辑器内容会自动更新,光标也会自动聚焦到第一个可编辑字段,无需手动调用任何方法。
3. Mention 扩展:@提及功能
Mention 扩展实现了类似社交平台的 @提及功能。输入触发字符(默认 @)会弹出选择列表,支持键盘导航(↑↓)和搜索过滤。
复制代码
输入 @ 触发提及选择,支持键盘导航和搜索过滤
Mention 扩展支持三个配置项:
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
items | MentionItem[] | Ref | [] | 提及项列表,支持响应式 ref |
char | string | '@' | 触发字符 |
allowSpaces | boolean | false | 是否允许触发字符后输入空格 |
4. Suggestion 扩展:智能联想与自定义过滤
Suggestion 扩展提供智能输入联想功能。用户输入时自动弹出建议列表,支持键盘导航和 Tab 自动补全。
复制代码
输入 ECS、CDN 或 OSS 查看分类联想,Tab 键快速补全
console.log('提交:', text)"
/>
Suggestion 配置项详解:
| 配置项 | 说明 | 类型 | 默认值 |
|---|---|---|---|
items | 建议项列表 | SenderSuggestionItem[] | [] |
filterFn | 自定义过滤函数,不传则不过滤 | (items, query) => items | undefined |
showAutoComplete | 显示灰色补全提示 | boolean | true |
activeSuggestionKeys | 激活建议的按键 | string[] | ['Enter'] |
popupWidth | 弹窗宽度(支持数字/百分比) | number | string | 400 |
onSelect | 选中回调,返回 false 阻止默认回填 | (item) => void | false | - |
5. VoiceButton:语音输入
VoiceButton 是一个独立的语音输入按钮组件,通过 footer 或 footer-right 插槽集成到 Sender 中。它同时支持浏览器内置的 Web Speech API 和自定义第三方语音识别服务。
复制代码
语音模式:
{{ voiceMode === 'mixed'
? '识别结果追加到输入框,可继续编辑修改'
: '持续识别并自动替换内容,适合长段语音输入' }}
{ content += transcript }"
/>
VoiceButton 核心配置:
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
speechConfig.autoReplace | 是否自动替换内容(false 则追加) | boolean | true |
speechConfig.continuous | 是否持续识别 | boolean | false |
speechConfig.interimResults | 是否返回中间结果 | boolean | false |
speechConfig.lang | 识别语言 | string | 浏览器默认语言 |
autoInsert | 是否自动插入识别结果到编辑器 | boolean | true |
如需集成阿里云、百度、Azure 等第三方语音服务,通过 speechConfig.customHandler 传入自定义处理器即可。
6. UploadButton:文件上传
UploadButton 允许用户上传文件(图片、文档等)作为对话的上下文输入,支持文件类型过滤、大小限制和数量限制。
复制代码
已选择:{{ uploadedFiles.map(f => f.name).join(', ') }}
UploadButton 核心配置:
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
accept | 接受的 MIME 类型 | string | '*' |
multiple | 是否支持多选 | boolean | false |
maxSize | 文件大小限制(MB) | number | - |
maxCount | 最大文件数量 | number | - |
tooltip | 悬停提示文本 | string | - |
7. 自定义插槽:灵活布局
Sender 提供多个插槽位置以支持灵活的布局扩展:
| 插槽 | 位置 | 作用域 | 典型用途 |
|---|---|---|---|
header | 输入框上方 | - | 标题、提示信息 |
prefix | 输入框内部左侧 | - | AI 图标、模型选择 |
content | 编辑器内容区域 | { editor } | 完全自定义编辑器内容 |
actions-inline | 单行模式操作区 | - | 单行模式下的操作按钮 |
footer | 底部左侧 | { editor, hasContent, disabled, loading } | 增强功能按钮 |
footer-right | 底部右侧 | - | 上传、语音按钮 |
复制代码
AI 智能助手
已输入 {{ content.length }} 字
console.log('选择文件:', files)"
/>
8. submitType:灵活控制提交流程
不同的应用场景需要不同的提交方式。Sender 通过 submitType 属性提供三种方式:
复制代码
提交方式:
快捷键行为对照表:
| submitType | 提交快捷键 | 换行快捷键 |
|---|---|---|
enter | Enter | Ctrl+Enter / Shift+Enter |
ctrlEnter | Ctrl+Enter | Enter |
shiftEnter | Shift+Enter | Enter |
结构化数据:读懂用户的意图
Sender 的 submit 事件不仅返回纯文本,当使用了 Template 或 Mention 扩展时,还会返回结构化的 data 参数,让你能够精确提取用户的意图。
复制代码// submit 事件签名
@submit="(text: string, data?: StructuredData) => { ... }"
Mention 结构化数据
复制代码const handleSubmit = (text: string, data?: StructuredData) => {
// 用户输入: "帮我分析 @代码助手 的代码质量"
// text: "帮我分析 @代码助手 的代码质量"
// data: [
// { type: 'text', content: '帮我分析 ' },
// { type: 'mention', content: '代码助手', value: 'you_are_a_coding_expert' },
// { type: 'text', content: ' 的代码质量' }
// ] // 提取提及的助手 ID 列表
const mentions = data?.filter(item => item.type === 'mention') || []
const assistantIds = mentions.map(item => item.value) // 自定义 Slack 风格格式
const customText = data?.map(item =>
item.type === 'mention' ? `<@${item.value}>` : item.content
).join('')
}
Template 结构化数据
复制代码const handleSubmit = (text: string, data?: StructuredData) => {
// 用户通过模板输入后提交
// text: "请帮我写一份关于人工智能的技术报告,字数要求3000字"
// data: [
// { type: 'text', content: '请帮我写一份关于' },
// { type: 'block', content: '人工智能' },
// { type: 'text', content: '的技术报告...' }
// ] // 提取所有可编辑块的值
const blocks = data?.filter(item => item.type === 'block') || []
const blockValues = blocks.map(b => b.content)
}
这种结构化设计让你可以轻松实现:
- 将 @提及转换为自定义协议格式
- 提取模板中的关键填充字段
- 构建更丰富的 AI 请求上下文
v0.4 升级与 SenderCompat 迁移
Sender 在 v0.4 版本进行了重大重构,底层从传统 textarea 升级为基于 Tiptap 的富文本编辑器,带来了更强大的扩展能力和更灵活的插槽系统。
如果你的项目正在使用 v0.3.x
TinyRobot 提供了 SenderCompat 兼容组件作为过渡方案,只需修改一行导入:
复制代码// 旧代码 (v0.3.x)
import { TrSender } from '@opentiny/tiny-robot'// 使用 SenderCompat 快速迁移
import { TrSenderCompat as TrSender } from '@opentiny/tiny-robot'
推荐的迁移路径:
复制代码v0.3.x Sender → SenderCompat(快速迁移,改导入即可)→ v0.4 Sender(按需完全升级)
v0.4 主要变更一览
| 变更类型 | v0.3.x | v0.4 | 说明 |
|---|---|---|---|
| 语音输入 | allow-speech prop | VoiceButton 独立组件 | 组件化设计,通过插槽集成 |
| 文件上传 | allow-files + button-group | UploadButton 独立组件 | 扁平化配置,更灵活 |
| 智能联想 | suggestions prop | Suggestion 扩展 | 通过 extensions 接入 |
| @提及 | - | Mention 扩展 | v0.4 新增功能 |
| 模板填充 | v-model:templateData | Template 扩展 | 响应式 ref 驱动 |
| 主题 | theme prop | ThemeProvider 包裹 | 全局继承,所有子组件自动生效 |
| 模板类型名 | type: 'template' | type: 'block' | 类型名称变更,需手动适配 |
完全升级到 v0.4
如果你准备完全升级到 v0.4,下面是一个典型的迁移对照:
复制代码
事件与方法速查
事件
| 事件名 | 说明 | 回调参数 |
|---|---|---|
update:modelValue | 内容更新 | (value: string) |
submit | 提交内容 | (text: string, data?: StructuredData) |
cancel | 取消操作(loading 状态下点击停止) | () |
clear | 清空内容 | () |
focus | 获得焦点 | (event: FocusEvent) |
blur | 失去焦点 | (event: FocusEvent) |
input | 输入变化 | (value: string) |
方法(通过 ref 调用)
| 方法 | 说明 | 参数 |
|---|---|---|
focus() | 使输入框获取焦点 | - |
blur() | 使输入框失去焦点 | - |
clear() | 清空输入内容 | - |
submit() | 手动触发提交 | - |
setContent(content) | 设置编辑器内容 | (content: string) |
getContent() | 获取编辑器内容 | - 返回 string |
cancel() | 手动触发取消 | - |
总结
TinyRobot Sender 通过以下设计原则,为 AI 聊天应用提供了企业级的输入体验:
- 可组合:各功能通过独立的扩展或组件实现,按需引入
- 响应式:扩展配置支持 Vue ref,数据变化自动同步 UI
- 结构化:submit 事件返回文本 + 结构化数据,精准传达用户意图
- 可插拔:Template、Mention、Suggestion 三大扩展独立运作,互不干扰
- 渐进迁移:通过 SenderCompat 兼容组件,平滑从 v0.3.x 升级
无论是构建一个简单的 AI 问答输入框,还是打造复杂的企业级 Copilot 交互界面,Sender 都能胜任。
