Skip to content
组件

Sender 消息输入框

Sender 是一个功能丰富的输入组件,支持文本输入、语音识别、文件上传、模板填充等多种输入方式。适用于聊天界面、评论输入、表单填写等场景。

代码示例

输入模式

Sender 支持单行和多行两种输入模式,通过 mode 属性控制。

单行模式自动切换

在单行模式下,当输入内容超出宽度或按 Shift+Enter 时,会自动切换为多行模式。

loading

状态控制

通过 loadingdisabled 属性控制组件状态。加载状态下可点击图标取消操作。

loading

内容管理

字数限制

通过 maxLengthshowWordLimit 属性实现字数限制和统计。

超出限制行为

超出字数限制时,不会自动截断内容,但会以红色标示真实字数,且无法提交。

loading

高度自适应

通过 autoSize 属性设置输入框根据内容自动调整高度(仅多行模式有效)。

loading

快速清空

通过 clearable 属性添加清空按钮,有内容时自动显示。

loading

输入增强

语音输入

基础语音识别

启用 allowSpeech 支持浏览器内置的语音识别功能。

loading

自定义语音服务

支持集成第三方语音识别服务(如阿里云、百度、Azure 等)。

loading

参考实现

speechHandlers.ts 提供了阿里云一句话识别和实时识别的完整示例,包括录音处理、API 调用、流式识别等。

自定义录音 UI

支持完全自定义语音录制界面,适用于移动端按住说话等场景。

loading

文件上传

通过 allowFiles 启用文件上传,结合 buttonGroup 可动态控制按钮状态和提示。

loading

模板填充

通过 v-model:templateData 实现模板的动态设置,光标自动聚焦到第一个可编辑字段。

loading

智能联想

根据用户输入显示匹配的建议项,支持键盘导航(↑↓ 选择,Enter/Tab 确认)和多种高亮模式。

loading

高亮模式

  • 自动匹配:传入对象数组,自动高亮与输入内容匹配的部分
  • 精确指定:通过 highlights 数组精确指定需要高亮的文本片段
  • 自定义函数:通过 highlights 函数完全控制高亮逻辑,实现复杂的高亮规则

过滤逻辑

组件不会自动过滤联想项,只负责高亮渲染匹配的部分。如需根据输入内容筛选建议项,请在传入 suggestions 之前自行过滤数组。

vue
<script setup>
import { ref, computed } from 'vue'

const inputText = ref('')
const allSuggestions = [
  { content: 'ECS-云服务器卡顿问题' },
  { content: 'CDN-权限管理' },
  // ...
]

// 根据输入内容过滤建议项
const filteredSuggestions = computed(() => {
  if (!inputText.value) return allSuggestions
  return allSuggestions.filter(item => 
    item.content.toLowerCase().includes(inputText.value.toLowerCase())
  )
})
</script>

<template>
  <tr-sender v-model="inputText" :suggestions="filteredSuggestions" />
</template>

激活按键配置

默认使用 EnterTab 键选中联想项,可通过 activeSuggestionKeys 属性自定义激活按键。详见 快捷键参考

交互定制

提交方式

通过 submitType 属性控制提交快捷键,支持 enterctrlEntershiftEnter 三种方式。

loading

快捷键参考

快捷键功能适用条件
Enter提交内容 / 选中联想项submitType="enter" / 联想开启时
Ctrl+Enter提交内容submitType="ctrlEnter"
Shift+Enter提交内容submitType="shiftEnter"
Tab选中联想项联想开启时
Esc取消语音/关闭联想对应功能激活时
↑ / ↓导航联想项联想开启时

自定义选中按键

通过 activeSuggestionKeys 可自定义选中联想项的按键,但请勿使用纯修饰键(Ctrl/Shift/Alt/Meta),避免劫持常用快捷键。

自定义按钮

通过 footer-leftfooter-right 插槽在底部区域添加自定义按钮。

loading

插槽布局

综合展示各种插槽的使用方式:

loading

装饰性内容

在输入框内显示提示信息,适用于服务状态提示、功能引导等场景。

自动禁用

使用 decorativeContent 插槽时,输入框会自动禁用,仅展示插槽内容。

loading

样式配置

紧凑模式

通过添加 tr-sender-compact CSS 类启用紧凑模式,适用于空间受限的场景。

loading

Props

属性名说明类型默认值
autofocus自动获取焦点booleanfalse
autoSize自动调整高度boolean | { minRows: number, maxRows: number }false
allowSpeech是否开启语音输入booleanfalse
allowFiles是否允许文件上传booleantrue
clearable是否可清空booleanfalse
disabled是否禁用booleanfalse
modelValue绑定值(v-model)string''
defaultValue默认值(非响应式)string''
loading是否加载中booleanfalse
mode输入框类型'single' | 'multiple''single'
maxLength最大输入长度numberInfinity
buttonGroup按钮组配置ButtonGroupConfig{}
placeholder输入框占位文本string'请输入内容...'
speech语音识别配置'boolean' | 'SpeechConfig'
showWordLimit是否显示字数统计booleanfalse
stopText停止按钮文字string仅显示图标
submitType提交方式'enter' | 'ctrl+enter' | 'shift+enter''enter'
theme主题样式'light' | 'dark''light'
suggestions输入建议列表(string | SuggestionItem)[][]
suggestionPopupWidth输入建议弹窗宽度'number' | 'string'400px
activeSuggestionKeys激活建议项的按键string[]['Enter', 'Tab']
templateData模板数据,用于初始化或 v-model 更新UserItem[][]

Slots

插槽名称描述默认内容
header头部插槽,位于输入框上方
prefix前缀插槽,位于输入框左侧
actions后缀插槽,位于输入框右侧单行模式下的操作按钮
content内容插槽输入内容区域
footer-left底部左侧插槽,保留字数限制字数限制
footer-right底部右侧插槽,保留操作按钮多行模式下的操作按钮
footer底部完全自定义插槽(向后兼容)无 (会覆盖其他底部元素)
decorativeContent装饰性内容插槽,启用后禁止输入

Events

事件名说明回调参数
update:modelValue输入值变化时触发(v-model)(value: string)
blur输入框失去焦点时触发(event: FocusEvent)
change输入值改变且失焦时触发(value: string)
focus输入框获得焦点时触发(event: FocusEvent)
input输入值改变时触发(value: string)
submit提交内容时触发(value: string)
clear清空内容时触发()
cancel取消发送(加载状态)时触发()
speech-start语音识别开始时触发()
speech-end语音识别结束时触发(transcript: string)
speech-interim语音识别中间结果时触发(transcript: string)
speech-error语音识别错误时触发(error: Error)
suggestion-select选择输入建议时触发(value: string)

Methods

方法名说明参数返回值
focus使输入框获取焦点-void
blur使输入框失去焦点-void
clear清空输入内容-void
submit手动触发提交事件-void
startSpeech开始语音识别-Promise<void>
stopSpeech停止语音识别-void
activateTemplateFirstField激活模板的第一个输入字段-void

Types

typescript
// 语音回调函数集合
interface SpeechCallbacks {
  onStart: () => void
  onInterim: (transcript: string) => void
  onFinal: (transcript: string) => void
  onEnd: (transcript?: string) => void
  onError: (error: Error) => void
}

// 自定义语音处理器接口
interface SpeechHandler {
  start: (callbacks: SpeechCallbacks) => Promise<void> | void
  stop: () => Promise<void> | void
  isSupported: () => boolean
}
interface SpeechConfig {
  customHandler?: SpeechHandler // 自定义语音处理器
  lang?: string // 识别语言,默认浏览器语言
  continuous?: boolean // 是否持续识别
  interimResults?: boolean // 是否返回中间结果
  autoReplace?: boolean // 是否自动替换当前输入内容
  onVoiceButtonClick?: (isRecording: boolean, preventDefault: () => void) => void | Promise<void> // 录音按钮点击拦截器
}
typescript
export interface ControlState {
  tooltips?: string | Function // 工具提示
  disabled?: boolean // 是否禁用
  tooltipPlacement?: 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end' // tooltip 弹窗位置
}

interface fileUploadConfig {
  accept?: string // 接受的文件类型
  multiple?: boolean // 是否支持多选文件
  reset?: boolean // 是否重置文件选择
}

interface VoiceButtonConfig {
  icon?: VNode | Component // 自定义语音图标(未录音状态)
}

interface ButtonGroupConfig {
  file?: ControlState & fileUploadConfig // 文件上传按钮
  submit?: ControlState // 提交按钮
  voice?: VoiceButtonConfig // 语音按钮
}
typescript
// 高亮文本片段类型
interface SuggestionTextPart {
  text: string;  // 文本片段
  isMatch: boolean;  // 是否高亮
}

// 高亮函数类型
type HighlightFunction = (suggestionText: string, inputText: string) => SuggestionTextPart[]

// 建议项类型
type SuggestionItem = string | {
  content: string;  // 建议项文本内容
  highlights?: string[] | HighlightFunction;  // 高亮方式
}