VUE工具之“vue3+ts的多选框搜索组件”
一、vue3+ts的多选框搜索组件
【ProductSKU】产品SKU查询使用【多个搜索】组件
<template> <MultipleSearch @search="handleSearch"/> </template> <script setup lang="ts"> import { defineEmits } from 'vue' import { MultipleSearch } from '@/components/ProductSKU' import { ProductApi } from "@/api/product/product"; const emit = defineEmits(['search']) const handleSearch = async (skuList) => { try { const data = await ProductApi.getProductPage({skuKeywordList:skuList}) emit('search', data) } catch (e) { console.error(e) } } </script> <style scoped lang="scss"> </style>
index.ts路由指定
import MultipleSearch from './src/MultipleSearch.vue' import ProductSKU from './src/ProductSKU.vue' export { MultipleSearch, ProductSKU }
【MultipleSearch】多个搜索组件
<template> <el-popover :visible="isShowDropdown" class="box-item" placement="bottom-end" popper-style="width: auto;" > <template #reference> <el-button :class="{'is-active': isShowDropdown}" @click="handleShowDropdown"> <el-icon><More /></el-icon> </el-button> </template> <div class="popover-container"> <el-scrollbar height="300px"> <div class="input-box"> <div class="input-item"> <div class="label">{{itemsLength}}</div> <el-input v-model="textareaValue" :autosize="true" type="textarea" placeholder="精确搜索,一行一项,最多支持2000行" @input="handleInput" /> </div> </div> </el-scrollbar> <div class="action-box"> <el-button @click="clearAll">清空</el-button> <el-button class="btn-close" @click="closePopover">关闭</el-button> <el-button @click="handleSearch">搜索</el-button> </div> </div> </el-popover> </template> <script setup lang="ts"> import { ref, onMounted, defineProps, defineEmits, computed } from 'vue' import { More } from '@element-plus/icons-vue' interface Props { // 每项的分隔符 delimiters?: string[] } const props = withDefaults(defineProps<Props>(), { delimiters: () => [',', '\n'] }) // 2. 明确 Emits 类型定义(指定事件参数类型) const emit = defineEmits<{ /** 搜索事件,触发时返回去重后的数组 */ (e: 'search', value: string[]): void }>() // 3. 状态变量补充类型定义 const isShowDropdown = ref<boolean>(false) // 下拉框显示状态 const textareaValue = ref<string>('') // 文本框输入值 const convertedList = ref<string[]>([]) // 分隔后去重的数组 // 4. 计算属性:有效项数(过滤空字符串) const itemsLength = computed((): number => { return convertedList.value.filter(item => item.trim() !== '').length }) // 5. 工具函数:创建分隔符正则表达式(避免重复创建) const createDelimiterRegExp = (delimiters: string[]): RegExp => { // 转义特殊正则字符(如 . * + ? 等),避免正则语法错误 const escapedDelimiters = delimiters.map(d => d.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) return new RegExp(`[${escapedDelimiters.join('|')}]+`, 'g') } // 6. 核心逻辑:将文本框值按分隔符转换为去重数组 const convertValueToList = (value: string): string[] => { const delimiterReg = createDelimiterRegExp(props.delimiters ?? [',', '\n']) // 步骤1:用正则替换所有分隔符为逗号 // 步骤2:去除首尾逗号 // 步骤3:按逗号分割为数组 // 步骤4:去重(保持原始顺序) const rawList = value.replace(delimiterReg, ',').replace(/^,|,$/g, '').split(',') return Array.from(new Set(rawList)) // 去重并保持数组类型 } // 7. 事件处理:文本框输入变化时更新数组 const handleInput = (): void => { convertedList.value = convertValueToList(textareaValue.value) } // 8. 事件处理:清空所有内容 const clearAll = (): void => { textareaValue.value = '' convertedList.value = [] } // 9. 事件处理:关闭下拉框并清空 const closePopover = (): void => { isShowDropdown.value = false clearAll() } const handleShowDropdown =(): void=>{ isShowDropdown.value = !isShowDropdown.value } // 10. 事件处理:触发搜索(传递去重后的有效数组) const handleSearch = (): void => { // 过滤空字符串,只传递有效项 const validList = convertedList.value.filter(item => item.trim() !== '') emit('search', validList) closePopover() } // 11. 生命周期:组件挂载后初始化(可根据需求添加逻辑) onMounted(() => { // 示例:初始化时若有默认值,可在这里处理 // convertedList.value = convertValueToList(textareaValue.value) }) </script> <style scoped lang="scss"> .el-button { padding: 0 5px; margin: 0; &.is-active, &:hover { background-color: #c5e0fa; color: #0655d5; } } .popover-container { width: 350px; .input-box { padding-top: 10px; .input-item { position: relative; margin-bottom: 10px; .label { position: absolute; top: 0; left: 10px; transform: translateY(-50%); font-size: 10px; z-index:1; color: #999; background-color: #fff; padding: 0 5px; } } } .action-box { display: flex; align-items: center; gap: 10px; padding: 10px 0 0; box-sizing: border-box; border-top: 1px solid #e0e0e0; .el-button{ margin: 0; } .btn-close { margin-left: auto; } } } </style>
* 博客文章部分截图及内容来自于学习的书本及相应培训课程,仅做学习讨论之用,不做商业用途。
* 如有侵权,马上联系我,我立马删除对应链接。
* 备注:王先生
* 我的网易邮箱:wzw_1314_520@163.com

浙公网安备 33010602011771号