如何开发支持多选功能的Searchfield搜索组件
实现支持多选的Searchfield搜索组件
核心需求梳理
- 支持多选功能:用户可选择多个下拉选项,已选项可直观展示并支持单独移除
- 兼容字符串类型下拉项的Model类:接收封装字符串字段的Model作为下拉数据源
- 提供搜索文本变更回调:输入框文本变化时立即触发指定函数,用于外部逻辑联动
实现要点
1. 多选状态管理
- 维护已选选项集合,用数组存储选中的Model实例(或其唯一标识+显示文本)
- 下拉项添加选中状态样式,点击时切换选中状态并更新已选集合
- 已选标签区域:支持点击移除单个选项,也可扩展清空全部功能
2. 数据源适配
- 接收泛型Model类(需包含字符串显示字段,如
label),提取字段作为下拉展示文本 - 搜索过滤时,基于Model的字符串字段做大小写不敏感的模糊匹配
3. 搜索回调触发
- 定义回调函数类型,参数为当前输入的搜索文本
- 绑定输入框的
input事件,文本变化时立即调用传入的回调函数
代码示例(Vue3 实现)
<template> <div class="search-multiselect"> <!-- 已选标签区 --> <div class="selected-tags"> <span v-for="item in selectedItems" :key="item.id" class="tag" > {{ item.label }} <button @click="removeSelected(item)" class="tag-close">×</button> </span> </div> <!-- 搜索输入框 --> <input v-model="searchText" @input="triggerSearchCallback" placeholder="搜索并选择..." class="search-input" /> <!-- 下拉选项列表 --> <ul v-if="filteredOptions.length" class="options-panel"> <li v-for="opt in filteredOptions" :key="opt.id" :class="{ 'is-selected': isItemSelected(opt) }" @click="toggleSelect(opt)" > {{ opt.label }} </li> </ul> </div> </template> <script setup> import { ref, computed } from 'vue' // 外部传入属性 const props = defineProps({ // 字符串类型下拉项的Model数组,结构示例:{ id: number, label: string } options: { type: Array, required: true }, // 搜索文本变更回调函数 onSearchChange: { type: Function, default: () => {} } }) // 内部状态 const searchText = ref('') const selectedItems = ref([]) // 过滤后的下拉选项 const filteredOptions = computed(() => { if (!searchText.value) return props.options const keyword = searchText.value.toLowerCase() return props.options.filter(opt => opt.label.toLowerCase().includes(keyword)) }) // 判断选项是否已选中 const isItemSelected = (option) => { return selectedItems.value.some(item => item.id === option.id) } // 切换选项选中状态 const toggleSelect = (option) => { const existsIdx = selectedItems.value.findIndex(item => item.id === option.id) if (existsIdx > -1) { selectedItems.value.splice(existsIdx, 1) } else { selectedItems.value.push(option) } } // 移除单个已选标签 const removeSelected = (item) => { const idx = selectedItems.value.findIndex(i => i.id === item.id) if (idx > -1) selectedItems.value.splice(idx, 1) } // 触发搜索文本变更回调 const triggerSearchCallback = () => { props.onSearchChange(searchText.value) } // 暴露已选结果给父组件 defineExpose({ selectedItems }) </script> <style scoped> .search-multiselect { position: relative; width: 350px; } .selected-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; } .tag { background-color: #f0f2f5; padding: 4px 8px; border-radius: 4px; display: flex; align-items: center; gap: 4px; font-size: 14px; } .tag-close { background: transparent; border: none; cursor: pointer; font-size: 16px; line-height: 1; } .search-input { width: 100%; padding: 8px 12px; border: 1px solid #dcdfe6; border-radius: 4px; font-size: 14px; } .options-panel { position: absolute; top: calc(100% + 4px); left: 0; right: 0; max-height: 220px; overflow-y: auto; border: 1px solid #dcdfe6; border-radius: 4px; background: #fff; list-style: none; padding: 0; margin: 0; } .options-panel li { padding: 8px 12px; cursor: pointer; font-size: 14px; } .options-panel li.is-selected { background-color: #e6f7ff; } .options-panel li:hover { background-color: #f5f7fa; } </style>
关键说明
- 组件通过
options属性接收Model数组,每个Model需包含唯一标识(如id)和字符串显示字段(如label) onSearchChange属性接收回调函数,输入框文本每一次变化都会传入当前文本值- 多选状态由
selectedItems数组维护,支持点击下拉项切换选中,或点击标签移除选项 - 搜索过滤逻辑可根据需求调整,比如支持精确匹配、多字段匹配等
内容的提问来源于stack exchange,提问作者Ganapathysriram M
相关产品推荐
相关产品推荐

