MentionSender 提及输入框 🦥
介绍
MentionSender
是用于聊天的输入框组件。
📌 注意
他和 Sender
组件的功能基本一样,唯一的区别就是 指令的弹框
相关的属性和方法 不同。点击此处快速了解区别 👉 指令区别
我们暂时没有考虑将 MentionSender
和 Sender
两个 指令功能 放到一起,仅仅通过组件进行区分。后续我们会在考虑将两个功能合并到另一个新的组件中: EditorSender
富文本输入框组件,去支持更多的输入框需求。
💡 提示
EditorSender
富文本框输入组件,将参考豆包的输入框,在未来和大家见面:

代码使用
这是一个MentionSender
输入框,最简答的使用例子,
<template>
<MentionSender />
</template>
2
3
可以通过 placeholder
设置输入框的提示语。
<template>
<MentionSender placeholder="💌 欢迎使用 Element-Plus-X ~" />
</template>
2
3
可以通过 v-model
绑定组件的 value
属性。
📌 注意
- 在提交时,需要有内容,才会进行提交。
- 内容为空时,提交按钮会被禁用,且使用组件实例提交会失效。
💌 消息
- 通过
v-model
属性,可以自动绑定输入框的值。不用赋值数据到v-model
中。 - 通过
@submit
事件,可以触发输入框的提交事件,回传一个value
参数,你可以在此处理提交的数据。 - 通过
@cancel
事件,可以触发loading
按钮的点击事件。在这里你可以中止提交的操作。
你也可以通过组件 ref 实例对象进行调用
senderRef.value.submit()
触发提交senderRef.value.cancel()
触发取消senderRef.value.clear()
重置输入框的值
<script setup lang="ts">
const senderRef = ref()
const timeValue = ref<NodeJS.Timeout | null>(null)
const senderValue = ref('')
const senderLoading = ref(false)
function handleSubmit(value: string) {
ElMessage.info(`发送中`)
senderLoading.value = true
timeValue.value = setTimeout(() => {
// 可以在控制台 查看打印结果
console.log('submit-> value:', value)
console.log('submit-> senderValue', senderValue.value)
senderLoading.value = false
ElMessage.success(`发送成功`)
}, 3500)
}
function handleCancel() {
senderLoading.value = false
if (timeValue.value)
clearTimeout(timeValue.value)
timeValue.value = null
ElMessage.info(`取消发送`)
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<div style="display: flex;">
<el-button type="primary" style="width: fit-content;" @click="senderRef.clear()">
使用组件实例清空
</el-button>
<el-button type="primary" style="width: fit-content;" :disabled="!senderValue" @click="senderRef.submit()">
使用组件实例提交
</el-button>
<el-button type="primary" style="width: fit-content;" @click="senderRef.cancel()">
使用组件实例取消
</el-button>
</div>
<MentionSender ref="senderRef" v-model="senderValue" :loading="senderLoading" clearable @submit="handleSubmit" @cancel="handleCancel" />
</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
可以通过 submit-btn-disabled
自定义 是否让发送按钮禁用。当禁用时,组件实例的 submit
方法将失效。
📌 注意
组件内置的 发送按钮,是更据 v-model
绑定的,所以,当 v-model
绑定的值为空时,发送按钮将处于禁用状态。
但是,有这么一个场景。用户通过上传了文件,但是没有输入内容,此时,发送按钮依然处于禁用状态。
所以,为了 禁用逻辑的解耦,组件提供了 submit-btn-disabled
属性,用于自主控制发送按钮的禁用状态。
自定义 #action-list
时,此属性对 submit 事件同样生效。
<script setup lang="ts">
const senderRef = ref()
const timeValue = ref<NodeJS.Timeout | null>(null)
const senderValue = ref('')
const senderLoading = ref(false)
const submitBtnDisabled = ref(true)
function handleSubmit(value: string) {
ElMessage.info(`发送中`)
senderLoading.value = true
timeValue.value = setTimeout(() => {
// 可以在控制台 查看打印结果
console.log('submit-> value:', value)
console.log('submit-> senderValue', senderValue.value)
senderLoading.value = false
ElMessage.success(`发送成功`)
}, 3500)
}
function handleCancel() {
senderLoading.value = false
if (timeValue.value)
clearTimeout(timeValue.value)
timeValue.value = null
ElMessage.info(`取消发送`)
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<span>这是内置的禁用逻辑:</span>
<Sender ref="senderRef" v-model="senderValue" :loading="senderLoading" clearable @submit="handleSubmit" @cancel="handleCancel" />
<span>自定义禁用逻辑:</span>
<Sender ref="senderRef" v-model="senderValue" :submit-btn-disabled="submitBtnDisabled" :loading="senderLoading" clearable @submit="handleSubmit" @cancel="handleCancel" />
</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
可以通过 autosize
设置输入框的最小展示行数和最大展示行数。 autosize
是一个对象 默认值为 { minRows: 1, maxRows: 6 }
。超出最大行数时,输入框会自动出现滚动条。
<script setup lang="ts">
const longerValue = `💌 欢迎使用 Element-Plus-X ~`.repeat(30)
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<MentionSender :auto-size="{ minRows: 2, maxRows: 5 }" />
<MentionSender v-model="longerValue" />
</div>
</template>
2
3
4
5
6
7
8
9
10
可以通过简单属性是,实现组件的状态
💌 消息
- 通过
loading
属性,可以控制输入框是否加载中。 - 通过
readOnly
属性,可以控制输入框是否可编辑。 - 通过
disabled
属性,可以控制输入框是否禁用。 - 通过
clearable
属性,可以控制输入框是否出现删除按钮,实现清空。 - 通过
inputWidth
属性,可以控制输入框的宽度。默认为100%
。
<script setup lang="ts">
const senderReadOnlyValue = ref(`只读:💌 欢迎使用 Element-Plus-X ~`)
const senderClearableValue = ref(`可删除:💌 欢迎使用 Element-Plus-X ~`)
function handleSubmit(value: string) {
console.log(value)
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<MentionSender loading placeholder="加载中..." @submit="handleSubmit" />
<MentionSender v-model="senderReadOnlyValue" read-only @submit="handleSubmit" />
<MentionSender value="禁用:💌 欢迎使用 Element-Plus-X ~" disabled @submit="handleSubmit" />
<MentionSender v-model="senderClearableValue" clearable @submit="handleSubmit" />
<MentionSender style="width: fit-content;" value="输入框最大宽度:💌 欢迎使用 Element-Plus-X ~" input-width="150px" @submit="handleSubmit" />
</div>
</template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
通过 submitType
控制换行与提交模式。默认 'enter'
。即 回车提交,'shift + Enter'
换行。
💌 消息
submitType='enter'
设置 回车提交,'shift + Enter'
换行。submitType='shiftEnter'
设置'shift + Enter'
提交,回车换行。
<script setup lang="ts">
const activeName = ref('enter')
const senderValue = ref('')
const senderLoading = ref(false)
function handleSubmit(value: string) {
ElMessage.info(`发送中`)
senderLoading.value = true
setTimeout(() => {
// 可以在控制台 查看打印结果
console.log('submit-> value:', value)
console.log('submit-> senderValue', senderValue.value)
senderLoading.value = false
ElMessage.success(`发送成功`)
}, 2000)
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<el-radio-group v-model="activeName">
<el-radio-button value="enter">
enter
</el-radio-button>
<el-radio-button value="shiftEnter">
shiftEnter
</el-radio-button>
</el-radio-group>
<MentionSender v-model="senderValue" :submit-type="activeName" :loading="senderLoading" @submit="handleSubmit" />
</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
内置 语音识别
功能,通过 allowSpeech
属性开启即可。调用浏览器原生的语音识别 API,在 谷歌浏览器
中使用,需要在 🪄魔法环境
中才能正常使用。
💌 消息
如果你不想使用内置的 语音识别
功能,可以通过 @recording-change
事件来监听录音状态,自行实现语音识别功能。
你也可以通过组件 ref 实例对象进行调用
senderRef.value.startRecognition()
触发开始录音senderRef.value.stopRecognition()
触发结束录音
<script setup lang="ts">
const senderRef = ref()
const senderValue = ref('')
function onRecordingChange(recording: boolean) {
if (recording) {
ElMessage.success('开始录音')
}
else {
ElMessage.success('结束录音')
}
}
function onsubmit() {
ElMessage.success('发送成功')
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<span>内置语音识别:</span>
<MentionSender v-model="senderValue" allow-speech @submit="onsubmit" />
<span>自定义语音识别:</span>
<div style="display: flex;">
<el-button
type="primary"
style="width: fit-content;"
@click="senderRef.startRecognition()"
>
使用组件实例 开始录音
</el-button>
<el-button
type="primary"
style="width: fit-content;"
@click="senderRef.stopRecognition()"
>
使用组件实例 结束录音
</el-button>
</div>
<MentionSender ref="senderRef" v-model="senderValue" allow-speech @recording-change="onRecordingChange" />
</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
📌 注意
1.0.81 版本
前,在自定义插槽的时候,会牺牲内置的操作按钮。我们在 1.0.81 版本
推出了流式请求的 hooks,可以让用户更好的控制流式请求,从而更好的自己定义 #action-list
插槽。详情请查看 useXStream。
此温馨提示更新时间:2025-04-06
通过 #action-list
插槽用于自定义输入框的操作列表内容。
💌 消息
当你使用 #action-list
插槽时,会隐藏内置的输入框的操作按钮。你可以通过和 组件实例方法
相结合,实现更丰富的操作。
<script setup lang="ts">
import { Delete, Loading, Operation, Position, Promotion, Right, Setting } from '@element-plus/icons-vue'
const senderRef = ref()
const senderValue = ref('')
const loading = ref(false)
function handleSubmit() {
console.log('submit', senderValue.value)
senderRef.value.submit()
loading.value = true
}
function handleCancel() {
console.log('cancel')
loading.value = false
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<MentionSender>
<!-- 自定义操作列表 -->
<template #action-list>
<div class="action-list-self-wrap">
<el-button type="danger" circle>
<el-icon><Delete /></el-icon>
</el-button>
<el-button type="primary" circle style="rotate: -45deg;">
<el-icon><Position /></el-icon>
</el-button>
</div>
</template>
</MentionSender>
<MentionSender>
<!-- 自定义操作列表 -->
<template #action-list>
<div class="action-list-self-wrap">
<el-button type="primary" plain circle color="#626aef">
<el-icon><Operation /></el-icon>
</el-button>
<el-button type="primary" circle color="#626aef">
<el-icon><Right /></el-icon>
</el-button>
</div>
</template>
</MentionSender>
<MentionSender>
<!-- 自定义操作列表 -->
<template #action-list>
<div class="action-list-self-wrap">
<el-button plain circle color="#eebe77">
<el-icon><Setting /></el-icon>
</el-button>
<el-button type="primary" plain circle>
<el-icon><Promotion /></el-icon>
</el-button>
</div>
</template>
</MentionSender>
<MentionSender ref="senderRef" v-model="senderValue" :loading="loading">
<!-- 自定义操作列表 -->
<template #action-list>
<div class="action-list-self-wrap">
<el-button v-if="loading" type="primary" plain circle @click="handleCancel">
<el-icon class="is-loaidng">
<Loading />
</el-icon>
</el-button>
<el-button v-else plain circle @click="handleSubmit">
<el-icon><Position /></el-icon>
</el-button>
</div>
</template>
</MentionSender>
</div>
</template>
<style scoped lang="less">
.action-list-self-wrap {
display: flex;
align-items: center;
& > span {
width: 120px;
font-weight: 600;
color: var(--el-color-primary);
}
}
.is-loaidng {
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</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
通过 #prefix
插槽用于自定义输入框的前缀内容。
<script setup lang="ts">
import { CircleClose, Link } from '@element-plus/icons-vue'
const senderRef = ref()
const senderValue = ref('')
const showHeaderFlog = ref(false)
onMounted(() => {
showHeaderFlog.value = true
senderRef.value.openHeader()
})
function openCloseHeader() {
if (!showHeaderFlog.value) {
senderRef.value.openHeader()
}
else {
senderRef.value.closeHeader()
}
showHeaderFlog.value = !showHeaderFlog.value
}
function closeHeader() {
showHeaderFlog.value = false
senderRef.value.closeHeader()
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px; height: 230px; justify-content: flex-end;">
<MentionSender ref="senderRef" v-model="senderValue">
<template #header>
<div class="header-self-wrap">
<div class="header-self-title">
<div class="header-left">
💯 欢迎使用 Element Plus X
</div>
<div class="header-right">
<el-button @click.stop="closeHeader">
<el-icon><CircleClose /></el-icon>
<span>关闭头部</span>
</el-button>
</div>
</div>
<div class="header-self-content">
🦜 自定义头部内容
</div>
</div>
</template>
<!-- 自定义前缀 -->
<template #prefix>
<div class="prefix-self-wrap">
<el-button dark>
<el-icon><Link /></el-icon>
<span>自定义前缀</span>
</el-button>
<el-button color="#626aef" :dark="true" @click="openCloseHeader">
打开/关闭头部
</el-button>
</div>
</template>
</MentionSender>
</div>
</template>
<style scoped lang="less">
.header-self-wrap {
display: flex;
flex-direction: column;
padding: 16px;
height: 200px;
.header-self-title {
width: 100%;
display: flex;
height: 30px;
align-items: center;
justify-content: space-between;
padding-bottom: 8px;
}
.header-self-content {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
color: #626aef;
font-weight: 600;
}
}
.prefix-self-wrap {
display: flex;
}
</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
通过 #header
插槽用于自定义输入框的头部内容。
💌 消息
通过组件实例控制 头部容器 展开收起
senderRef.value.openHeader()
打开头部容器senderRef.value.closeHeader()
关闭头部容器
<script setup lang="ts">
import { CircleClose } from '@element-plus/icons-vue'
const senderRef = ref()
const senderValue = ref('')
const showHeaderFlog = ref(false)
onMounted(() => {
showHeaderFlog.value = true
senderRef.value.openHeader()
})
function openCloseHeader() {
if (!showHeaderFlog.value) {
senderRef.value.openHeader()
}
else {
senderRef.value.closeHeader()
}
showHeaderFlog.value = !showHeaderFlog.value
}
function closeHeader() {
showHeaderFlog.value = false
senderRef.value.closeHeader()
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px; height: 300px; justify-content: space-between;">
<el-button style="width: fit-content;" @click="openCloseHeader">
{{ showHeaderFlog ? '关闭头部' : '打开头部' }}
</el-button>
<MentionSender ref="senderRef" v-model="senderValue">
<template #header>
<div class="header-self-wrap">
<div class="header-self-title">
<div class="header-left">
💯 欢迎使用 Element Plus X
</div>
<div class="header-right">
<el-button @click.stop="closeHeader">
<el-icon><CircleClose /></el-icon>
<span>关闭头部</span>
</el-button>
</div>
</div>
<div class="header-self-content">
🦜 自定义头部内容
</div>
</div>
</template>
</MentionSender>
</div>
</template>
<style scoped lang="less">
.header-self-wrap {
display: flex;
flex-direction: column;
padding: 16px;
height: 200px;
.header-self-title {
width: 100%;
display: flex;
height: 30px;
align-items: center;
justify-content: space-between;
padding-bottom: 8px;
}
.header-self-content {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
color: #626aef;
font-weight: 600;
}
}
</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
通过 ref 选项控制聚焦。
💌 消息
通过组件实例控制
senderRef.value.focus('all')
聚焦到整个文本 (默认)senderRef.value.focus('start')
聚焦到文本最前方senderRef.value.focus('end')
聚焦到文本最后方senderRef.value.blur()
失去焦点
<script setup lang="ts">
const senderRef = ref()
const senderValue = ref('🐳 欢迎使用 Element Plus X')
function blur() {
senderRef.value.blur()
}
function focus(type = 'all') {
senderRef.value.focus(type)
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px;">
<div style="display: flex;">
<el-button dark type="success" plain @click="focus('start')">
文本最前方
</el-button>
<el-button dark type="success" plain @click="focus('end')">
文本最后方
</el-button>
<el-button dark type="success" plain @click="focus('all')">
整个文本
</el-button>
<el-button dark type="success" plain @click="blur">
失去焦点
</el-button>
</div>
<MentionSender ref="senderRef" v-model="senderValue" />
</div>
</template>
<style scoped lang="less">
.header-self-wrap {
display: flex;
flex-direction: column;
padding: 16px;
height: 200px;
.header-self-title {
width: 100%;
display: flex;
height: 30px;
align-items: center;
justify-content: space-between;
padding-bottom: 8px;
}
.header-self-content {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
color: #626aef;
font-weight: 600;
}
}
</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
通过 variant
属性设置输入框的变体。默认 'default' | 上下结构 'updown'
这个属性,将左右结构的 输入框,变成 上下结构的 输入框。上面为 输入框,下面为 内置的 前缀和操作列表栏
<script setup lang="ts">
import { ElementPlus, Paperclip, Promotion } from '@element-plus/icons-vue'
const senderValue = ref('')
const isSelect = ref(false)
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender v-model="senderValue" variant="updown" />
<MentionSender v-model="senderValue" variant="updown" clearable />
<MentionSender v-model="senderValue" variant="updown" clearable allow-speech />
<MentionSender v-model="senderValue" variant="updown" :auto-size="{ minRows: 2, maxRows: 5 }" clearable allow-speech placeholder="💌 在这里你可以自定义变体后的 prefix 和 action-list">
<template #prefix>
<div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
<el-button round plain color="#626aef">
<el-icon><Paperclip /></el-icon>
</el-button>
<div :class="{ isSelect }" style="display: flex; align-items: center; gap: 4px; padding: 2px 12px; border: 1px solid silver; border-radius: 15px; cursor: pointer; font-size: 12px;" @click="isSelect = !isSelect">
<el-icon><ElementPlus /></el-icon>
<span>深度思考</span>
</div>
左边是自定义 prefix 前缀 右边是自定义 操作列表
</div>
</template>
<template #action-list>
<div style="display: flex; align-items: center; gap: 8px;">
<el-button round color="#626aef">
<el-icon><Promotion /></el-icon>
</el-button>
</div>
</template>
</MentionSender>
</div>
</template>
<style scoped lang="scss">
.isSelect {
color: #626aef;
border: 1px solid #626aef !important;
border-radius: 15px;
padding: 3px 12px;
font-weight: 700;
}
</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
通过 #footer
插槽设置输入框 底部内容
💌 消息
如果你想要设置 #footer
插槽,不想要 updown 变体的内置布局,可以再添加 showUpdown
属性,隐藏 updown 变体的内置布局
<script setup lang="ts">
import { ElementPlus, Paperclip, Promotion } from '@element-plus/icons-vue'
const senderValue = ref('')
const isSelect = ref(false)
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender v-model="senderValue" :auto-size="{ minRows: 1, maxRows: 5 }" clearable allow-speech placeholder="💌 欢迎使用 Element-Plus-X">
<template #prefix>
<div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
<el-button round plain color="#626aef">
<el-icon><Paperclip /></el-icon>
</el-button>
</div>
</template>
<template #action-list>
<div style="display: flex; align-items: center; gap: 8px;">
<el-button round color="#626aef">
<el-icon><Promotion /></el-icon>
</el-button>
</div>
</template>
<!-- 自定义 底部插槽 -->
<template #footer>
<div style="display: flex; align-items: center; justify-content: center; padding: 12px;">
默认变体 自定义底部
</div>
</template>
</MentionSender>
<MentionSender v-model="senderValue" variant="updown" :auto-size="{ minRows: 2, maxRows: 5 }" clearable allow-speech placeholder="💌 在这里你可以自定义变体后的 prefix 和 action-list">
<template #prefix>
<div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
<el-button round plain color="#626aef">
<el-icon><Paperclip /></el-icon>
</el-button>
<div :class="{ isSelect }" style="display: flex; align-items: center; gap: 4px; padding: 2px 12px; border: 1px solid silver; border-radius: 15px; cursor: pointer; font-size: 12px;" @click="isSelect = !isSelect">
<el-icon><ElementPlus /></el-icon>
<span>深度思考</span>
</div>
</div>
</template>
<template #action-list>
<div style="display: flex; align-items: center; gap: 8px;">
<el-button round color="#626aef">
<el-icon><Promotion /></el-icon>
</el-button>
</div>
</template>
<!-- 自定义 底部插槽 -->
<template #footer>
<div style="display: flex; align-items: center; justify-content: center; padding: 12px;">
updown 变体 自定义底部
</div>
</template>
</MentionSender>
<MentionSender v-model="senderValue" variant="updown" :auto-size="{ minRows: 2, maxRows: 5 }" clearable allow-speech placeholder="💌 通过设置 showUpdown 为 false 隐藏 updown 变体的内置布局" :show-updown="false">
<template #prefix>
<div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
<el-button round plain color="#626aef">
<el-icon><Paperclip /></el-icon>
</el-button>
<div :class="{ isSelect }" style="display: flex; align-items: center; gap: 4px; padding: 2px 12px; border: 1px solid silver; border-radius: 15px; cursor: pointer; font-size: 12px;" @click="isSelect = !isSelect">
<el-icon><ElementPlus /></el-icon>
<span>深度思考</span>
</div>
</div>
</template>
<template #action-list>
<div style="display: flex; align-items: center; gap: 8px;">
<el-button round color="#626aef">
<el-icon><Promotion /></el-icon>
</el-button>
</div>
</template>
<!-- 自定义 底部插槽 -->
<template #footer>
<div style="display: flex; align-items: center; justify-content: center; padding: 12px; text-align: center;">
showUpdown 属性 隐藏 updown 变体内置布局样式 + #footer 底部插槽结合,完全让你来控制底部内容
</div>
</template>
</MentionSender>
</div>
</template>
<style scoped lang="scss">
.isSelect {
color: #626aef;
border: 1px solid #626aef !important;
border-radius: 15px;
padding: 3px 12px;
font-weight: 700;
}
</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
通过 input-style
方便对输入框的样式透传
<script setup lang="ts">
import { ElementPlus, Paperclip, Promotion } from '@element-plus/icons-vue'
const senderValue = ref('这是自定义输入框样式')
const isSelect = ref(false)
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender v-model="senderValue" variant="updown" :input-style="{ backgroundColor: 'rgb(243 244 246)', color: '#626aef', fontSize: '24px', fontWeight: 700 }" style="background: rgb(243 244 246); border-radius: 8px;" />
<MentionSender v-model="senderValue" variant="updown" :input-style="{ backgroundColor: 'transparent', color: '#F0F2F5', fontSize: '24px', fontWeight: 700 }" style="background-image: linear-gradient(to left, #434343 0%, black 100%); border-radius: 8px;" />
<MentionSender v-model="senderValue" :input-style="{ backgroundColor: 'transparent', color: '#FF5454', fontSize: '20px', fontWeight: 700 }" style="background-image: linear-gradient(to top, #fdcbf1 0%, #fdcbf1 1%, #e6dee9 100%); border-radius: 8px;" />
<MentionSender v-model="senderValue" variant="updown" :input-style="{ backgroundColor: 'transparent', color: '#303133', fontSize: '16px', fontWeight: 700 }" style="background-image: linear-gradient(to top, #d5d4d0 0%, #d5d4d0 1%, #eeeeec 31%, #efeeec 75%, #e9e9e7 100%); border-radius: 8px;">
<template #prefix>
<div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
<el-button round plain color="#626aef">
<el-icon><Paperclip /></el-icon>
</el-button>
<div :class="{ isSelect }" style="display: flex; align-items: center; gap: 4px; padding: 2px 12px; border: 1px solid black; border-radius: 15px; cursor: pointer; font-size: 12px; color: black;" @click="isSelect = !isSelect">
<el-icon><ElementPlus /></el-icon>
<span>深度思考</span>
</div>
</div>
</template>
<template #action-list>
<div style="display: flex; align-items: center; gap: 8px;">
<el-button round color="#626aef">
<el-icon><Promotion /></el-icon>
</el-button>
</div>
</template>
</MentionSender>
</div>
</template>
<style scoped lang="scss">
.isSelect {
color: #626aef !important;
border: 1px solid #626aef !important;
border-radius: 15px;
padding: 3px 12px;
font-weight: 700;
}
</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
📌 注意
下面展示和 Sender
组件 不一样 的指令相关 属性方法。使用时请注意 使用区别
此温馨提示更新时间:2025-04-16
- 通过
options
属性,可以传入一个数组,用于定义提及选项列表。 - 通过
triggerStrings
属性 触发字段的前缀。 这里和Sender
组价不同,这里的字符串长度必须且只能为 1。
// options 提及选项列表的 类型定义
interface MentionOption {
value: string
label?: string
disabled?: boolean
[key: string]: any
}
2
3
4
5
6
7
💌 消息
光设置 options
属性,不能开启提及功能。需要 triggerStrings
属性来开启提及功能。
<script setup lang="ts">
const senderValue = ref('')
const options = [
{
value: 'value1',
label: '选项1',
},
{
value: 'value2',
label: '选项2',
disabled: true,
},
{
value: 'value3',
label: '选项3',
},
]
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender
v-model="senderValue"
placeholder="输入 / 触发指令弹框"
clearable
:options="options"
:trigger-strings="['/']"
/>
</div>
</template>
<style scoped lang="scss">
</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
通过 triggerStrings
属性 触发字段。这里和 Sender
组价不同,这里的字符串长度必须且只能为 1。类型是 Array<string>
。
如果需要通过 多个字符串触发,可以搭配 @search
事件控制显示浮层内容。
💌 消息
光设置 options
属性,不能开启提及功能。需要 triggerStrings
属性来开启提及功能。
<script setup lang="ts">
import type { MentionOption } from '../types'
const senderValue = ref('')
const MOCK_DATA: Record<string, string[]> = {
'@': ['Element-Plus-X', 'HeJiaYue520', 'JsonLee12138', 'lisentowind', 'ZRMYDYCG'],
'#': ['1.0', '2.0', '3.0', '4.0', '5.0'],
}
const options = ref<MentionOption[]>([])
function handleSearch(_: string, prefix: string) {
console.log('handleSearch', _, prefix)
options.value = (MOCK_DATA[prefix] || []).map(value => ({
value,
}))
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender
v-model="senderValue"
placeholder="输入 @ 和 # 触发指令弹框"
clearable
:options="options"
:trigger-strings="['@', '#']"
@search="handleSearch"
/>
</div>
</template>
<style scoped lang="scss">
</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
用于拆分提及的字符。 字符串长度必须且只能为 1,默认为 ' '
。
<script setup lang="ts">
import type { MentionOption } from '../types'
const senderValue1 = ref('')
const options = ref<MentionOption[]>([
{
value: 'HeJiaYue520',
avatar: 'https://avatars.githubusercontent.com/u/76239030',
},
{
value: 'JsonLee12138',
avatar: 'https://avatars.githubusercontent.com/u/160690954',
},
{
value: 'ageerle',
avatar: 'https://avatars.githubusercontent.com/u/32251822',
},
])
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender
v-model="senderValue1"
placeholder="输入 @ 触发指令弹框"
:options="options"
:trigger-strings="['@']"
trigger-split="、"
:whole="true"
>
<template #trigger-label="{ item }">
<div style="display: flex; align-items: center">
<el-avatar :size="24" :src="item.avatar" />
<span style="margin-left: 6px">{{ item.value }}</span>
</div>
</template>
</MentionSender>
</div>
</template>
<style scoped lang="scss">
</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
通过 triggerLoading
属性设置 提及选项列表的加载状态。triggerLoading
属性默认为 false
,即默认不显示加载状态。
<script setup lang="ts">
import type { MentionOption } from '../types'
const senderValue = ref('')
const MOCK_DATA: Record<string, string[]> = {
'@': ['Element-Plus-X', 'HeJiaYue520', 'JsonLee12138', 'lisentowind', 'ZRMYDYCG'],
'#': ['1.0', '2.0', '3.0', '4.0', '5.0'],
}
const options = ref<MentionOption[]>([])
const triggerLoading = ref(false)
function handleSearch(_: string, prefix: string) {
triggerLoading.value = true
setTimeout(() => {
console.log('handleSearch', _, prefix)
options.value = (MOCK_DATA[prefix] || []).map(value => ({
value,
}))
triggerLoading.value = false
}, 1500)
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender
v-model="senderValue"
placeholder="输入 @ 和 # 触发指令弹框"
clearable
:options="options"
:trigger-strings="['@', '#']"
:trigger-loading="triggerLoading"
@search="handleSearch"
/>
</div>
</template>
<style scoped lang="scss">
</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
通过 filter-option
定制筛选器选项逻辑,通过一个方法,返回为true
或 false
来控制选项的过滤结果,你也可以理解为搜索的过滤逻辑。
类型是 (pattern: string, option: MentionOption) => boolean
<script setup lang="ts">
import type { MentionOption } from '../types'
const senderValue1 = ref('')
const options = ref<MentionOption[]>([
{
value: 'HeJiaYue520',
avatar: 'https://avatars.githubusercontent.com/u/76239030',
},
{
value: 'JsonLee12138',
avatar: 'https://avatars.githubusercontent.com/u/160690954',
},
{
value: 'ageerle',
avatar: 'https://avatars.githubusercontent.com/u/32251822',
},
])
function filterFunc(_: string, option: MentionOption) {
// 这里打印 option 每次触发指令,会遍历 options 触发 filterFunc。
if (option.value === 'ageerle' || option.value === 'JsonLee12138') {
return true
}
else if (option.value === 'HeJiaYue520') {
return false
}
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender
v-model="senderValue1"
placeholder="输入 @ 触发指令弹框,此处已经过滤了 HeJiaYue520"
:options="options"
:trigger-strings="['@']"
trigger-split=","
:whole="true"
:filter-option="filterFunc"
>
<template #trigger-label="{ item }">
<div style="display: flex; align-items: center">
<el-avatar :size="24" :src="item.avatar" />
<span style="margin-left: 6px">{{ item.value }}</span>
</div>
</template>
</MentionSender>
</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
-
将
whole
属性设置为true
,当您按下退格键时,此处的mention
区域将作为一个整体被删除。 -
设置
check-is-whole
属性来自定义检查逻辑。当你需要做多个条件时,你可以使用check-is-whole
属性来自定义检查逻辑。 -
check-is-whole 属性不是事件,类型为 (pattern: string, prefix: string) => boolean 返回
true
表示匹配成功要被整体删除,返回false
表示匹配失败不会被整体删除。 默认为true
<script setup lang="ts">
import type { MentionOption } from '../types'
const senderValue1 = ref('')
const senderValue2 = ref('')
const MOCK_DATA: Record<string, string[]> = {
'@': ['Element-Plus-X', 'HeJiaYue520', 'JsonLee12138', 'lisentowind', 'ZRMYDYCG'],
'#': ['1.0', '2.0', '3.0', '4.0', '5.0'],
}
const options = ref<MentionOption[]>([])
function handleSearch(_: string, prefix: string) {
options.value = (MOCK_DATA[prefix] || []).map(value => ({
value,
}))
}
function checkIsWhole(pattern: string, prefix: string) {
console.log('checkIsWhole', pattern, prefix)
return (MOCK_DATA[prefix] || []).includes(pattern)
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender
v-model="senderValue1"
placeholder="单个指令整体删除:输入 @ 触发指令弹框"
clearable
:options="options"
:trigger-strings="['@']"
:whole="true"
@search="handleSearch"
/>
<MentionSender
v-model="senderValue2"
placeholder="多个指令整体删除:输入 @ 和 # 触发指令弹框"
clearable
:options="options"
:trigger-strings="['@', '#']"
whole
:check-is-whole="checkIsWhole"
@search="handleSearch"
/>
</div>
</template>
<style scoped lang="scss">
</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
通过 trigger-popover-placement
设置 弹出方向。默认是 'top'
, 可以设置为 'bottom'
。目前只支持 'top'
和 'bottom'
两种。
<script setup lang="ts">
import type { MentionOption } from '../types'
const senderValue1 = ref('')
const MOCK_DATA: Record<string, string[]> = {
'@': ['Element-Plus-X', 'HeJiaYue520', 'JsonLee12138', 'lisentowind', 'ZRMYDYCG'],
'#': ['1.0', '2.0', '3.0', '4.0', '5.0'],
}
const options = ref<MentionOption[]>([])
function handleSearch(_: string, prefix: string) {
options.value = (MOCK_DATA[prefix] || []).map(value => ({
value,
}))
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender
v-model="senderValue1"
placeholder="输入 @ 和 / 触发指令弹框"
clearable
:options="options"
:trigger-strings="['@', '/']"
:whole="true"
trigger-popover-placement="bottom"
@search="handleSearch"
/>
</div>
</template>
<style scoped lang="scss">
</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
通过 triggerPopoverOffset
属性可以设置浮层距离窗口的偏移量。默认值 20,表示为 20px。
<script setup lang="ts">
import type { MentionOption } from '../types'
const senderValue1 = ref('')
const MOCK_DATA: Record<string, string[]> = {
'@': ['Element-Plus-X', 'HeJiaYue520', 'JsonLee12138', 'lisentowind', 'ZRMYDYCG'],
'#': ['1.0', '2.0', '3.0', '4.0', '5.0'],
}
const options = ref<MentionOption[]>([])
function handleSearch(_: string, prefix: string) {
options.value = (MOCK_DATA[prefix] || []).map(value => ({
value,
}))
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender
v-model="senderValue1"
placeholder="输入 @ 和 / 触发指令弹框 当前偏移量50px"
clearable
:options="options"
:trigger-strings="['@', '/']"
:whole="true"
trigger-popover-placement="bottom"
:trigger-popover-offset="50"
@search="handleSearch"
/>
</div>
</template>
<style scoped lang="scss">
</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
💌 消息
- 支持
#trigger-label
自定义 标签内容,每条数据的展示 - 支持
#trigger-loading
自定义 加载中状态,当triggerLoading
为 true 时,会显示加载中状态 - 支持
#trigger-header
自定义 下拉列表顶部的内容 - 支持
#trigger-footer
自定义 下拉列表底部的内容
<script setup lang="ts">
import type { MentionOption } from '../types'
import { Loading } from '@element-plus/icons-vue'
const senderValue1 = ref('')
const options = ref<MentionOption[]>()
const triggerLoading = ref(false)
function handleSearch() {
triggerLoading.value = true
setTimeout(() => {
options.value = [
{
value: 'HeJiaYue520',
avatar: 'https://avatars.githubusercontent.com/u/76239030',
},
{
value: 'JsonLee12138',
avatar: 'https://avatars.githubusercontent.com/u/160690954',
},
{
value: 'ageerle',
avatar: 'https://avatars.githubusercontent.com/u/32251822',
},
]
triggerLoading.value = false
}, 1500)
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender
v-model="senderValue1"
placeholder="输入 @ 触发指令弹框"
:options="options"
:trigger-strings="['@']"
:whole="true"
:trigger-loading="triggerLoading"
@search="handleSearch"
>
<template #trigger-label="{ item }">
<div style="display: flex; align-items: center">
<el-avatar :size="24" :src="item.avatar" />
<span style="margin-left: 6px">{{ item.value }}</span>
</div>
</template>
<template #trigger-loading>
<div style="display: flex; align-items: center; justify-content: center; height: 100%; padding: 24px; gap: 12px;">
这是自定义加载中状态
<el-icon class="is-loading" style="color: cornflowerblue; font-size: 20px;">
<Loading />
</el-icon>
</div>
</template>
<template #trigger-header>
<div style="display: flex; align-items: center; justify-content: center; height: 100%; padding: 8px;">
这是自定义下拉列表顶部的内容
</div>
</template>
<template #trigger-footer>
<div style="display: flex; align-items: center; justify-content: center; height: 100%; padding: 8px;">
这是自定义下拉列表底部的内容
</div>
</template>
</MentionSender>
</div>
</template>
<style scoped lang="scss">
</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
按下触发字段时触发
<script setup lang="ts">
import type { MentionOption } from '../types'
const senderValue1 = ref('')
const options = ref<MentionOption[]>([
{
value: 'HeJiaYue520',
avatar: 'https://avatars.githubusercontent.com/u/76239030',
},
{
value: 'JsonLee12138',
avatar: 'https://avatars.githubusercontent.com/u/160690954',
},
{
value: 'ageerle',
avatar: 'https://avatars.githubusercontent.com/u/32251822',
},
])
const filterOptions = ref()
function handleSearch(searchValue: string, prefix: string) {
console.log('搜索的值', searchValue)
console.log('弹框触发的 字符前缀', prefix) // 这里可以判断多 指令的情况
// 当调用出弹框后,每次输入的时候,都会调用这个方法。
filterOptions.value = options.value.filter((option) => {
// 这里的 option.value 是 '@' 后面的内容
// 所以这里需要判断是否包含输入的内容
if (searchValue) {
return option.value.includes(searchValue)
}
else {
// 如果没有输入内容,则显示所有选项
return option
}
})
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender
v-model="senderValue1"
placeholder="输入 @ 触发指令弹框,此处已经过滤了 HeJiaYue520"
:options="filterOptions"
:trigger-strings="['@']"
trigger-split=","
:whole="true"
@search="handleSearch"
>
<template #trigger-label="{ item }">
<div style="display: flex; align-items: center">
<el-avatar :size="24" :src="item.avatar" />
<span style="margin-left: 6px">{{ item.value }}</span>
</div>
</template>
</MentionSender>
</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
当用户选择选项时触发
<script setup lang="ts">
import type { MentionOption } from '../types'
const senderValue1 = ref('')
const options = ref<MentionOption[]>([
{
value: 'HeJiaYue520',
avatar: 'https://avatars.githubusercontent.com/u/76239030',
},
{
value: 'JsonLee12138',
avatar: 'https://avatars.githubusercontent.com/u/160690954',
},
{
value: 'ageerle',
avatar: 'https://avatars.githubusercontent.com/u/32251822',
},
])
const filterOptions = ref()
function handleSearch(searchValue: string, prefix: string) {
console.log('搜索的值', searchValue)
console.log('弹框触发的 字符前缀', prefix) // 这里可以判断多 指令的情况
// 当调用出弹框后,每次输入的时候,都会调用这个方法。
filterOptions.value = options.value.filter((option) => {
// 这里的 option.value 是 '@' 后面的内容
// 所以这里需要判断是否包含输入的内容
if (searchValue) {
return option.value.includes(searchValue)
}
else {
// 如果没有输入内容,则显示所有选项
return option
}
})
}
function handleSelect(option: MentionOption) {
console.log('选中的值', option)
ElMessage.success(`选中的值:${option.value}`)
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 20px;">
<MentionSender
v-model="senderValue1"
placeholder="输入 @ 触发指令弹框,此处已经过滤了 HeJiaYue520"
:options="filterOptions"
:trigger-strings="['@']"
trigger-split=","
:whole="true"
@search="handleSearch"
@select="handleSelect"
>
<template #trigger-label="{ item }">
<div style="display: flex; align-items: center">
<el-avatar :size="24" :src="item.avatar" />
<span style="margin-left: 6px">{{ item.value }}</span>
</div>
</template>
</MentionSender>
</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
属性
属性名 | 类型 | 是否必填 | 默认值 | 说明 |
---|---|---|---|---|
v-model | String | 否 | '' | 输入框的绑定值,使用 v-model 进行双向绑定。 |
placeholder | String | 否 | '' | 输入框的提示语文本。 |
auto-size | Object | 否 | { minRows:1, maxRows:6 } | 设置输入框的最小展示行数和最大展示行数。 |
read-only | Boolean | 否 | false | 输入框是否为只读状态。 |
disabled | Boolean | 否 | false | 输入框是否为禁用状态。 |
submitBtnDisabled v1.1.6版本新增 | Boolean | undefined | 否 | undefined | 内置发送按钮禁用状态。(注意使用场景) |
loading | Boolean | 否 | false | 是否显示加载状态。为 true 时,输入框会显示加载动画。 |
clearable | Boolean | 否 | false | 输入框是否可清空内容。展示默认清空按钮 |
allowSpeech | Boolean | 否 | false | 是否允许语音输入。默认展示内置语音识别按钮,内置浏览器内置语音识别 API |
submitType | String | 否 | 'enter' | 提交方式,支持 'shiftEnter' (按 Shift + Enter 提交)。 |
headerAnimationTimer | Number | 否 | 300 | 输入框的自定义头部显示时长,单位为 ms 。 |
inputWidth | String | 否 | '100%' | 输入框的宽度。 |
variant v1.1.6版本新增 | String | 否 | 'default' | 输入框的变体类型,支持 'default' 、'updown' 。 |
showUpdown v1.1.6版本新增 | Boolean | 否 | true | 当变体为 updown 时,是否展示内置样式。 |
inputStyle v1.1.6版本新增 | Object | 否 | {} | 输入框的样式。 |
triggerStrings v1.1.6版本新增 | string[] | 否 | [] | 触发指令的 字符串数组 。 |
triggerPopoverVisible v1.1.6版本新增 | Boolean | 否 | false | 触发指令的 弹框 是否可见。需要使用 v-model:triggerPopoverVisible 进行控制。 |
triggerPopoverWidth v1.1.6版本新增 | String | 否 | 'fit-content' | 触发指令的 弹框 的宽度。可使用百分比等css单位。 |
triggerPopoverLeft v1.1.6版本新增 | String | 否 | '0px' | 触发指令的 弹框 的左边距。可使用百分比等css单位。 |
triggerPopoverOffset v1.1.6版本新增 | Number | 否 | 8 | 触发指令的 弹框 的左边距。只能是数字类型,单位px |
triggerPopoverPlacement v1.1.6版本新增 | String | 否 | 'top-start' | 触发指令的 弹框 的位置。取值:'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end' |
事件
事件名 | 说明 | 回调参数 |
---|---|---|
submit | 内置 提交按钮 提交时触发的事件。 | 无 |
cancel | 内置 loading按钮 点击时触发的事件。 | 无 |
recordingChange | 内置语音识别状态变化时触发的事件。 | 无 |
trigger v1.1.6版本新增 | 指令弹框发生变化时触发的事件。 | interface TriggerEvent{oldValue: string; newValue: string; isOpen: boolean; } |
Ref 实例方法
属性名 | 类型 | 描述 |
---|---|---|
openHeader | Function | 打开输入框的自定义头部。 |
closeHeader | Function | 关闭输入框的自定义头部。 |
clear | Function | 清空输入框的内容。 |
blur | Function | 移除输入框的焦点。 |
focus | Function | 聚焦输入框。 默认 focus('all') 聚焦整个文本,focus('start') 聚焦文本最前方,focus('end') 聚焦文本最后方。 |
submit | Function | 提交输入内容。 |
cancel | Function | 取消加载状态。 |
startRecognition | Function | 开始语音识别。 |
stopRecognition | Function | 停止语音识别。 |
插槽
插槽名 | 参数 | 类型 | 描述 |
---|---|---|---|
#header | - | Slot | 用于自定义输入框的头部内容。 |
#prefix | - | Slot | 用于自定义输入框的前缀内容。 |
#action-list | - | Slot | 用于自定义输入框的操作列表内容。 |
#footer v1.1.6版本新增 | - | Slot | 用于自定义输入框的尾部内容。 |
功能特性
- 焦点控制:支持将焦点设置到文本最前方、最后方或选中整个文本,也可取消焦点。
- 自定义内容:提供头部、前缀、操作列表等插槽,允许用户自定义这些部分的内容。
- 提交功能:支持按
Shift + Enter
提交输入内容,提交后可执行自定义操作。 - 加载状态:可显示加载状态,模拟提交处理过程。
- 语音输入:支持语音输入功能,提升输入的便捷性。
- 清空功能:输入框可清空内容,方便用户重新输入。