【Vue3】如何封装一个支持输入和单/多选InputSelect组件-Antd

写在前面:

Antd提供的select组件是不支持当作输入框使用的,并且不支持在一级状态下手动输入选项,所以就封装了一个和通用组件来实现上述功能。

组件效果:

单选模式:

多选模式:

实现步骤:

1.首先定义一个searchText存储用户输入的数据,因为会触发一个Antd定义的@Search事件,所以直接在onSearch数据收集即可

js 复制代码
const searchText = ref('')
const onSearch = val => {
  // 去除首尾空格
  const text = val.trim()
  if (text) {
    searchText.value = text
  }
}

2.定义三个prop控制输入的数据,组件模式以及是否允许输入

js 复制代码
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清空,以便下一次输入。

js 复制代码
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

js 复制代码
<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>

完整代码:

js 复制代码
<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>

使用范例:

单选:

js 复制代码
    <InputSelect
      v-model:value="record.name"
      placeholder="请选择或输入"
      :options="headerOptions"
      allow-clear
      show-search
      max-tag-count="responsive"
     />

多选:

js 复制代码
<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"
 />
相关推荐
charlie1145141911 天前
HTML 理论笔记
开发语言·前端·笔记·学习·html·1024程序员节
刚子编程1 天前
ASP.NET Core Blazor 路由配置和导航
服务器·javascript·.netcore·blazor
海鸥两三1 天前
Uni-App(Vue3 + TypeScript)项目结构详解 ------ 以 Lighting-UniApp 为例,提供源代码
vue.js·typescript·uni-app·1024程序员节
知识分享小能手1 天前
uni-app 入门学习教程,从入门到精通,uni-app 企业项目实战:鲁嗑瓜子项目开发知识点(9)
前端·javascript·学习·微信小程序·小程序·uni-app·vue
阿金要当大魔王~~1 天前
uniapp img 动态渲染 的几种用法
java·服务器·前端·1024程序员节
知识分享小能手1 天前
uni-app 入门学习教程,从入门到精通,uni-app中uCharts组件学习((8)
vue.js·学习·ui·微信小程序·小程序·uni-app·echarts
one.dream1 天前
用webpack 插件实现 img 图片的懒加载
前端·webpack·node.js
布兰妮甜1 天前
彻底清理:Vue项目中移除static文件夹的完整指南
vue.js·前端框架·static·1024程序员节
打小就很皮...1 天前
Steps + Input.TextArea + InfiniteScroll 联调优化
前端·react.js
皓月Code1 天前
第四章、路由配置
前端·javascript·react.js·1024程序员节