You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何开发支持多选功能的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">&times;</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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 15:01:11