写在前面:
Antd提供的select组件是不支持当作输入框使用的,并且不支持在一级状态下手动输入选项,所以就封装了一个和通用组件来实现上述功能。
组件效果:
单选模式:
多选模式:
实现步骤:
1.首先定义一个searchText
存储用户输入的数据,因为会触发一个Antd
定义的@Search
事件,所以直接在onSearch
数据收集即可
const searchText = ref('')
const onSearch = val => {
// 去除首尾空格
const text = val.trim()
if (text) {
searchText.value = text
}
}
2.定义三个prop
控制输入的数据,组件模式以及是否允许输入
const props = defineProps({
value: {
type: [Array, String, Number],
default: undefined
},
mode: {
type: String,
default: ''
},
allowInputValue: {
type: Boolean,
default: true
}
})
3.在组件失焦时完成数据传递,其实组件功能的核心就是在失焦时完成
首先,通过条件判断allowInputValue.value && searchText.value
判断是否允许输入且存在搜索文本。
如果条件成立,继续执行下面的逻辑。
接着,通过判断tempMode.value === 'multiple'
判断选择模式是否为多选。
如果选择模式为多选,则将搜索文本searchText.value
添加到tempValue.value
的数组中,即将搜索文本作为一个新的选项添加到选中值中。
如果选择模式不是多选,则直接将搜索文本赋值给tempValue.value
,即将搜索文本作为选中值。
然后,通过emit('change', tempValue.value)
触发change
事件,并将当前的选中值作为参数传递给父组件。
最后,将searchText.value
清空,以便下一次输入。
const emit = defineEmits(['update:value', 'update:mode', 'change'])
//组件失去焦点
const onBlur = () => {
if (allowInputValue.value && searchText.value) {
if (tempMode.value === 'multiple') {
tempValue.value.push(searchText.value)
} else {
tempValue.value = searchText.value
}
emit('change', tempValue.value)
searchText.value = ''
}
}
4.定义$attrs
以及slot
支持进一步拓展及支持a-select原生api
<template>
<a-select
v-bind="$attrs"
v-model:value="tempValue"
:mode="tempMode"
@search="onSearch"
@blur="onBlur"
@change="onChange"
>
<template v-for="(item, key, index) in $slots" :key="index" #[key]>
<slot :name="key"></slot>
</template>
</a-select>
</template>
完整代码:
<template>
<a-select
v-bind="$attrs"
v-model:value="tempValue"
:mode="tempMode"
@search="onSearch"
@blur="onBlur"
@change="onChange"
>
<template v-for="(item, key, index) in $slots" :key="index" #[key]>
<slot :name="key"></slot>
</template>
</a-select>
</template>
<script setup>
import { computed, ref, toRefs } from 'vue'
const props = defineProps({
value: {
type: [Array, String, Number],
default: undefined
},
mode: {
type: String,
default: ''
},
allowInputValue: {
type: Boolean,
default: true
}
})
const emit = defineEmits(['update:value', 'update:mode', 'change'])
const { value, mode, allowInputValue } = toRefs(props)
const tempValue = computed({
set: val => emit('update:value', val),
get: () => value.value
})
const tempMode = computed({
set: val => emit('update:mode', val),
get: () => mode.value
})
const searchText = ref('')
const onSearch = val => {
// 去除首尾
const text = val.trim()
if (text) {
searchText.value = text
}
}
const onBlur = () => {
if (allowInputValue.value && searchText.value) {
if (tempMode.value === 'multiple') {
tempValue.value.push(searchText.value)
} else {
tempValue.value = searchText.value
}
emit('change', tempValue.value)
searchText.value = ''
}
}
const onChange = () => {
emit('change', tempValue.value)
searchText.value = ''
}
</script>
<style lang="scss" scoped></style>
使用范例:
单选:
<InputSelect
v-model:value="record.name"
placeholder="请选择或输入"
:options="headerOptions"
allow-clear
show-search
max-tag-count="responsive"
/>
多选:
<InputSelect
v-model:value="modelRef.actList"
class="value-item"
mode="multiple"
placeholder="请选择或输入"
:options="ACT_TYPES"
allow-clear
show-search
max-tag-count="responsive"
@change="onChange"
/>
原文链接:https://juejin.cn/post/7317821499868200960 作者:掉毛的小羊羔