FluxSelectMultiple 技术设计文档
MultipleSelectPro 多选组件技术设计文档
1. 设计背景
在现代 Web 应用中,多选组件是非常常见的交互元素。特别是在数据分析、内容管理、用户配置等场景下,用户经常需要从大量选项中选择多个条目。传统的多选组件在处理大数据量时往往存在以下问题:
业务痛点
- 性能瓶颈:当选项数量达到几千甚至几万时,传统组件会出现明显的渲染卡顿
- 用户体验差:大量 DOM 节点导致滚动不流畅,操作响应延迟
- 功能单一:缺乏高效的搜索、批量操作等功能
- 可扩展性差:难以适配复杂的业务场景和自定义需求
应用场景
2. 设计目标
核心目标
- 高性能:支持万级数据量的流畅操作
- 易用性:提供直观的用户交互体验
- 可扩展:支持自定义渲染和复杂业务逻辑
- 一致性:与 TDesign 设计规范保持一致
技术要求
- 基于 Vue 3.5+ 和 Composition API
- 使用 TDesign Vue Next 作为基础 UI 库
- 支持 TypeScript 类型检查
- 兼容现代浏览器
3. 架构设计
3.1 整体架构
MultipleSelectPro
├── 主组件 (multiple-select-pro.vue)
├── 子组件
│ └── DropdownList (下拉列表容器)
│ └── ListItem (虚拟列表项)
├── Hooks
│ ├── useOptionsList (选项列表管理)
│ └── useCheck (选中状态管理)
├── 类型定义 (types.ts)
└── 样式文件├── _index.less (组件样式)└── _global.less (全局样式)
3.2 核心模块
主组件 (multiple-select-pro.vue)
- 负责整体 UI 布局和用户交互
- 集成搜索、标签展示、下拉面板等功能
- 管理组件状态和事件分发
DropdownList 组件
- 抽象下拉列表的渲染逻辑
- 支持虚拟滚动和懒加载两种模式
- 处理选项的选中/取消逻辑
Hooks 设计
- useOptionsList:管理选项数据的转换、搜索、高亮等逻辑
- useCheck:处理选中状态、全选、反选等操作
4. 核心技术方案
4.1 虚拟滚动实现
虚拟滚动是解决大数据量渲染性能问题的核心技术:
<!-- DropdownList 组件中的虚拟滚动实现 -->
<template v-if="scroll.type === 'virtual'"><VirtualListclass="checkbox-group":data-key="'value'":data-sources="options":data-component="ListItem":extra-props="{values: value,max,checkboxProps: {disabled,readonly,name,},onChange,}"/>
</template>
技术原理:
- 使用
vue3-virtual-scroll-list
库实现虚拟滚动 - 只渲染可视区域内的 DOM 节点(通常 20-50 个)
- 动态计算滚动位置和可见项目范围
- 支持动态高度和不定高度项目
性能提升:
- 30,000 条数据仅渲染可见的 ~30 个 DOM 节点
- 内存占用降低 99%+,渲染时间从秒级降低到毫秒级
4.2 高效数据结构设计
使用 Set 数据结构优化选中状态管理:
// useCheck.ts 中的 Set 优化
const valueSet = shallowRef(new Set(value.value));// Set 工具函数
const setUtils = {// O(n) 时间复杂度的子集判断isSubsetOf: <T>(setA: Set<T>, setB: Set<T>): boolean => {for (const value of setA) {if (!setB.has(value)) return false;}return true;},// O(n+m) 时间复杂度的并集操作union: <T>(setA: Set<T>, setB: Set<T>): Set<T> => {const result = new Set(setA);setB.forEach(value => result.add(value));return result;},// O(n) 时间复杂度的差集操作difference: <T>(setA: Set<T>, setB: Set<T>): Set<T> => {const result = new Set<T>();setA.forEach(value => {if (!setB.has(value)) result.add(value);});return result;},
};
优势对比:
Set.has()
查找:O(1) vs 数组includes()
:O(n)- 大数据量下性能提升 100-1000 倍
- 内存效率更高,避免重复值
4.3 响应式优化策略
浅响应式优化
// 使用 shallowRef 避免深度响应式代理
const valueSet = shallowRef(new Set(value.value));
原理:
shallowRef
只代理第一层引用,不深度代理 Set 内部元素- 减少响应式系统开销,提升大数据量场景下的性能
- 保持必要的响应式能力
计算属性缓存
const enabledSearchedValueSet = computed(() =>SEARCHED_OPTIONS_LIST.value.reduce((set, cur) => {if (!cur.disabled) set.add(cur.value);return set;}, new Set<string | number>())
);
优势:
- 依赖项不变时避免重复计算
- 自动缓存计算结果
- 减少不必要的 DOM 更新
4.4 智能搜索与高亮
多关键词搜索
// useOptionsList.ts 中的搜索逻辑
const searchTerms = compositionFilter.value.enable? textLower.split(reg).filter(term => term.trim() !== ''): [textLower];const filterOption = ({ item, terms, highlightColor }) => {const matchedTerms = terms.filter(term => item.label.toLowerCase().includes(term) || toString(item.value).toLowerCase().includes(term));if (matchedTerms.length > 0) {return {...item,label: highlightText(item.label, matchedTerms.join(', '), highlightColor),};}return null;
};
特性:
- 支持多分隔符:换行、中英文逗号、自定义分隔符
- 同时搜索 label 和 value 字段
- 实时高亮匹配关键词
- 正则表达式转义,支持特殊字符搜索
高亮渲染
const highlightText = (text: string, highlightKey: string, highlightColor: string) => {const escapedHighlightKey = highlightKey.split(', ').map(term => term.replace(