当前位置: 首页 > backend >正文

Vue3+AntDesign实现带搜索功能的下拉单选组件

目录

一、需求如下

功能说明

关键实现点

二、效果图

三、代码结构图

四、实现代码


详细需求设计文档,及实施任务请参见本篇文章:

设计文档和需求文档及实施计划-CSDN博客文章浏览阅读169次。本文档描述了一个集成企查查云端检索功能的智能下拉选择器组件,采用Vue 3和Ant Design Vue实现。组件包含本地搜索、云端检索、数据选择三大核心功能,支持通过API与企查查服务交互。文档详细说明了组件架构、接口定义、数据模型及核心实现逻辑,包括本地选项过滤、云端检索触发条件判断、API调用封装以及选择结果回显机制。组件设计考虑了错误处理、数据验证和用户体验,提供了完整的搜索选择解决方案。 https://blog.csdn.net/nndsb/article/details/150352714?spm=1011.2415.3001.5331

Gitee 代码仓储:https://gitee.com/lzm52cml/vue3_demo1.githttps://gitee.com/lzm52cml/vue3_demo1.git

一、需求如下

实现一个带搜索功能的下拉单选组件,左侧为支持搜索的下拉框,中间按钮默认隐藏(仅当搜索无结果时显示),右侧为提示文本。当搜索无匹配项时,展示按钮;点击按钮弹出含单选表格的弹窗,选中数据后关闭弹窗并将指定字段回显至下拉框。该交互需满足:

1)下拉框搜索匹配时隐藏按钮

2)弹窗表格支持单选

3) 数据回显功能。

功能说明

  1. 搜索功能:下拉框支持输入搜索,实时过滤选项
  2. 动态按钮:当搜索无结果时显示添加按钮,有匹配结果时隐藏
  3. 弹窗交互:点击按钮弹出含单选表格的模态框
  4. 数据回显:从表格选择数据后自动关闭弹窗并回显到下拉框
  5. 自定义配置:支持通过props传递选项数据、表格数据、列配置等

关键实现点

  • 使用show-search属性启用Ant Design Select的搜索功能
  • 通过filteredOptions计算属性实现搜索过滤逻辑
  • 使用showAddButton计算属性控制按钮显示状态
  • 通过rowSelection配置实现表格单选功能
  • 使用v-model:value实现双向数据绑定

该组件已完整实现需求中的所有交互功能,可根据实际项目需求调整样式和配置参数。

二、效果图

三、代码结构图

四、实现代码

<template><div class="searchable-dropdown-container"><!-- 主要搜索区域 --><div class="dropdown-section"><label class="dropdown-label">客户单位名称</label><a-selectv-model:value="selectedValue"show-searchplaceholder="请选择单位名称"class="dropdown-select":filter-option="false":options="filteredOptions"@search="handleSearch"@change="handleSelectionChange"@keydown="handleKeyDown"ref="selectRef"><template #notFoundContent><div v-if="showNoResultsMessage" class="no-results-content"><div class="no-results-text">没有找到匹配的单位信息</div><div class="help-message">您可以点击启动企查查云端检索查询<br />若单位未在企查查内登记,请联系CRM管理员</div></div></template></a-select></div><!-- 云端检索按钮区域 --><div class="button-section"><a-buttonv-if="showCloudSearchButton"type="primary"class="cloud-search-button":loading="loading"@click="openCloudSearchModal">启动企查查云端检索</a-button></div><!-- 右侧提示文本 --><div class="help-text-section"><span class="help-text">{{ helpText }}</span></div></div><!-- 云端检索弹窗 --><a-modalv-model:open="modalVisible"title="企查查单位查询"width="800px":confirm-loading="loading"@ok="handleModalConfirm"@cancel="handleModalCancel"><a-table:columns="tableColumns":data-source="cloudSearchResults"row-key="id":pagination="false":row-selection="rowSelection":loading="loading"size="small"/></a-modal>
</template><script setup>
import { ref, computed, nextTick } from 'vue'
import { message } from 'ant-design-vue'
import { debounce } from './utils/debounce'// 组件引用
const selectRef = ref(null)// 原始下拉选项
const options = ref([{ label: '阿里巴巴集团', value: 'alibaba' },{ label: '腾讯科技有限公司', value: 'tencent' },{ label: '百度在线网络技术公司', value: 'baidu' },{ label: '京东集团', value: 'jd' },{ label: '网易公司', value: 'netease' },{ label: '新浪微博', value: 'weibo' }
])// 响应式状态
const selectedValue = ref(null)
const searchValue = ref('')
const loading = ref(false)
const modalVisible = ref(false)
const selectedRowKeys = ref([])
const highlightedIndex = ref(-1)// 右侧提示文本
const helpText = ref('请输入单位名称进行搜索,如果找不到可以使用云端检索功能')// 云端检索结果数据
const cloudSearchResults = ref([{ id: 1, name: '字节跳动有限公司', code: '91110108MA01', address: '北京市海淀区知春路63号' },{ id: 2, name: '小米科技有限责任公司', code: '9111010855', address: '北京市海淀区西二旗中路33号' },{ id: 3, name: '美团点评', code: '9111010877', address: '北京市朝阳区望京东路6号' }
])// 表格列配置
const tableColumns = [{ title: '单位名称', dataIndex: 'name', key: 'name', width: '40%' },{ title: '统一社会信用代码', dataIndex: 'code', key: 'code', width: '30%' },{ title: '注册地址', dataIndex: 'address', key: 'address', width: '30%' }
]// 防抖函数已从 utils/debounce.js 导入// 计算属性:过滤后的选项(大小写不敏感)
const filteredOptions = computed(() => {if (!searchValue.value || searchValue.value.trim() === '') {return options.value}const searchTerm = searchValue.value.toLowerCase().trim()return options.value.filter(option => option.label.toLowerCase().includes(searchTerm))
})// 计算属性:是否显示无结果消息
const showNoResultsMessage = computed(() => {return searchValue.value && searchValue.value.trim() !== '' && filteredOptions.value.length === 0
})// 计算属性:是否显示云端检索按钮
const showCloudSearchButton = computed(() => {return searchValue.value && searchValue.value.trim() !== '' && filteredOptions.value.length === 0
})// 防抖搜索处理函数
const debouncedSearch = debounce((value) => {searchValue.value = valuehighlightedIndex.value = -1 // 重置高亮索引
}, 300)// 搜索处理
const handleSearch = (value) => {debouncedSearch(value)
}// 选择变化处理
const handleSelectionChange = (value) => {selectedValue.value = valuesearchValue.value = '' // 清空搜索值highlightedIndex.value = -1
}// 键盘导航处理
const handleKeyDown = (event) => {const { key } = eventconst visibleOptions = filteredOptions.valueif (visibleOptions.length === 0) returnswitch (key) {case 'ArrowDown':event.preventDefault()highlightedIndex.value = Math.min(highlightedIndex.value + 1, visibleOptions.length - 1)breakcase 'ArrowUp':event.preventDefault()highlightedIndex.value = Math.max(highlightedIndex.value - 1, 0)breakcase 'Enter':event.preventDefault()if (highlightedIndex.value >= 0 && highlightedIndex.value < visibleOptions.length) {const selectedOption = visibleOptions[highlightedIndex.value]handleSelectionChange(selectedOption.value)}breakcase 'Escape':event.preventDefault()searchValue.value = ''highlightedIndex.value = -1if (selectRef.value) {selectRef.value.blur()}break}
}// 表格单选配置
const rowSelection = computed(() => ({type: 'radio',selectedRowKeys: selectedRowKeys.value,onChange: (selectedKeys) => {selectedRowKeys.value = selectedKeys}
}))// 打开云端检索弹窗
const openCloudSearchModal = () => {modalVisible.value = trueselectedRowKeys.value = []
}// 弹窗确认处理
const handleModalConfirm = () => {if (selectedRowKeys.value.length === 0) {message.warning('请选择一个单位')return}const selectedRow = cloudSearchResults.value.find(row => row.id === selectedRowKeys.value[0])if (selectedRow) {// 检查是否已存在,避免重复添加const existingOption = options.value.find(opt => opt.value === selectedRow.code)if (!existingOption) {options.value.push({label: selectedRow.name,value: selectedRow.code})}// 设置选中值并关闭弹窗selectedValue.value = selectedRow.codemodalVisible.value = falseselectedRowKeys.value = []searchValue.value = ''message.success('单位选择成功')}
}// 弹窗取消处理
const handleModalCancel = () => {modalVisible.value = falseselectedRowKeys.value = []
}// 搜索相关函数已移至 utils/searchUtils.js
</script><style scoped>
.searchable-dropdown-container {display: flex;align-items: center;gap: 16px;padding: 16px;border-bottom: 1px solid #eee;
}.dropdown-section {display: flex;align-items: center;gap: 8px;
}.dropdown-label {margin-right: 8px;white-space: nowrap;font-weight: 500;
}.dropdown-select {width: 250px;
}.button-section {flex-shrink: 0;
}.cloud-search-button {white-space: nowrap;
}.help-text-section {flex: 1;margin-left: 16px;
}.help-text {color: #ff4d4f;font-size: 14px;line-height: 1.4;
}.no-results-content {padding: 8px 12px;text-align: center;
}.no-results-text {margin-bottom: 4px;color: #999;font-weight: 500;
}.help-message {color: #999;font-size: 12px;line-height: 1.4;
}/* 响应式设计 */
@media (max-width: 768px) {.searchable-dropdown-container {flex-direction: column;align-items: stretch;gap: 12px;}.dropdown-section {flex-direction: column;align-items: stretch;gap: 8px;}.dropdown-select {width: 100%;}.help-text-section {margin-left: 0;}
}
</style>
{"name": "my-vue3-antd-app-no-jsx","version": "1.0.0","private": true,"scripts": {"dev": "vite","build": "vite build","preview": "vite preview","test": "vitest","test:run": "vitest run"},"dependencies": {"ant-design-vue": "^4.2.3","vue": "^3.4.0"},"devDependencies": {"@vitejs/plugin-vue": "^5.0.4","@vue/test-utils": "^2.4.0","jsdom": "^23.0.0","vite": "^5.2.0","vitest": "^1.0.0"}
}

http://www.xdnf.cn/news/17709.html

相关文章:

  • 如何生成.patch?
  • 2025年AI大模型应用架构设计十大核心问题深度解析
  • Java pdf工具
  • Java 导出word 实现表格内插入图表(柱状图、折线图、饼状图)--可编辑数据
  • 飞算JavaAI的中间件风暴:Redis + Kafka 全链路实战
  • Android 在 2020-2025 都做哪些更新?
  • 浏览器面试题及详细答案 88道(23-33)
  • Pytorch FSDP权重分片保存与合并
  • CW32L011电机开发板控制教程
  • MVCC底层实现原理
  • Java Web开发:Session与Cookie详细入门指南
  • 深入理解 C++ 中的虚函数:原理、特点与使用场景
  • mac下载maven并配置,以及idea配置
  • 智慧城市数字孪生:城市管理的“平行宇宙”
  • nginx匹配规则
  • 计算机网络体系结构
  • framebuffer
  • 当GitHub宕机时,我们如何保持高效协作?分布式策略与应急方案详解
  • 建设有人文温度的智能社会:规划与实施路径
  • 2小时构建生产级AI项目:基于ViT的图像分类流水线(含数据清洗→模型解释→云API)(第十七章)
  • BGP综合实验_Te. BGP笔记
  • 德文识别技术:为德语用户创造更智能、更便捷的信息处理体验
  • wps--设置
  • Android 终端接入 GB28181 国标视频平台的完整解决方案解析
  • HarmonyOS 开发实战:搞定应用名字与图标更换,全流程可运行示例
  • 玩转Docker | 使用Docker部署WordPress网站服务
  • 深度学习与遥感入门(七)|CNN vs CNN+形态学属性(MP):特征工程到底值不值?
  • 基于R语言的现代贝叶斯统计学方法(贝叶斯参数估计、贝叶斯回归、贝叶斯计算)实践
  • MySQL数据库知识体系总结 20250813
  • 疏老师-python训练营-Day44预训练模型