Vue3.0实战:JeecgBoot项目中BasicTable父子组件联动全选功能实现(附完整代码)
Vue3.0实战JeecgBoot项目中BasicTable父子组件联动全选功能深度解析在复杂的企业级后台系统中表格数据的层级展示与批量操作是高频需求场景。本文将以JeecgBoot框架为基础深入剖析Vue3.0组合式API在BasicTable组件中实现父子级联选择的完整技术方案同时分享实际开发中的性能优化技巧和常见问题解决方案。1. 需求分析与技术选型1.1 业务场景还原典型的多级表格交互通常存在以下核心需求父级选择框勾选时自动选中所有子项子项全部选中时自动勾选父级选择框部分子项选中时父级显示半选状态支持跨层级的状态同步更新在JeecgBoot的权限管理系统、订单处理等模块中这类交互模式能显著提升批量操作的效率。例如部门-员工层级管理订单-商品明细批量处理分类-子分类数据导出1.2 技术实现对比方案优点缺点事件冒泡机制实现简单适合浅层级结构深层嵌套时逻辑复杂Vuex状态管理状态集中管理便于调试中小项目显得臃肿组合式API响应式引用逻辑复用性强性能最优需要理解Vue3响应式原理经过实际验证我们选择基于Vue3的组合式API实现其核心优势在于// 典型响应式引用声明 const parentSelectedKeys ref([]) const childSelectedKeys ref({})2. 核心实现逻辑拆解2.1 父子选择状态联动父级选择控制子级const handleParentSelect (parent, selected) { // 更新父级选中状态 parentSelectedKeys.value selected ? [...parentSelectedKeys.value, parent.id] : parentSelectedKeys.value.filter(k k ! parent.id) // 递归更新子级状态 const updateChildren (children) { children.forEach(child { childSelectedKeys.value[parent.id] selected ? [...new Set([...childSelectedKeys.value[parent.id] || [], child.childId])] : (childSelectedKeys.value[parent.id] || []).filter(k k ! child.childId) if (child.children) updateChildren(child.children) }) } updateChildren(parent.children || []) }子级选择影响父级const handleChildSelect (child, selected, parent) { // 更新当前子级状态 childSelectedKeys.value[parent.id] selected ? [...childSelectedKeys.value[parent.id] || [], child.childId] : (childSelectedKeys.value[parent.id] || []).filter(k k ! child.childId) // 检查是否全选 const allSelected parent.children.every(c (childSelectedKeys.value[parent.id] || []).includes(c.childId) ) // 同步父级状态 if (allSelected !parentSelectedKeys.value.includes(parent.id)) { parentSelectedKeys.value [...parentSelectedKeys.value, parent.id] } else if (!allSelected parentSelectedKeys.value.includes(parent.id)) { parentSelectedKeys.value parentSelectedKeys.value.filter(k k ! parent.id) } }2.2 性能优化关键点内存优化方案使用Map替代Object存储子级选中状态采用WeakMap管理临时计算数据实现选择状态的分级懒加载提示对于超大规模数据(1000条)建议实现虚拟滚动可视区域状态管理可参考以下配置const virtualScrollOptions { height: 600, itemSize: 54, buffer: 10 }3. JeecgBoot集成实践3.1 BasicTable特殊配置JeecgBoot的BasicTable组件需要特殊处理以下属性const parentRowSelection { selectedRowKeys: parentSelectedKeys, onChange: handleParentSelect, columnWidth: 40, checkStrictly: false, getCheckboxProps: record ({ indeterminate: checkIndeterminate(record) }) }关键参数说明checkStrictly: false启用父子联动indeterminate实现半选状态显示columnWidth控制选择框列宽3.2 扩展行处理技巧对于可展开的嵌套表格需要特别注意BasicTable :expandedRowKeysexpandedRowKeys expandhandleExpand template #expandedRowRender{ record } ChildTable :parentRecordrecord / /template /BasicTable常见问题解决方案展开状态丢失维护expandedRowKeys数组子表滚动错位固定父表列宽性能卡顿使用v-if替代v-show控制子表渲染4. 企业级应用增强方案4.1 状态持久化实现// 使用localStorage保存选中状态 watch([parentSelectedKeys, childSelectedKeys], () { localStorage.setItem(table-selection, JSON.stringify({ parent: parentSelectedKeys.value, children: childSelectedKeys.value })) }, { deep: true }) // 初始化时恢复状态 onMounted(() { const saved JSON.parse(localStorage.getItem(table-selection)) if (saved) { parentSelectedKeys.value saved.parent childSelectedKeys.value saved.children } })4.2 多页签协同处理在JeecgBoot的多页签环境中需要处理以下特殊情况跨页签状态同步批量操作冲突检测异步加载时的状态回填推荐采用事件总线模式const eventBus mitt() // 发送选择事件 eventBus.emit(selection-change, { tabId: currentTab.id, selection: getCurrentSelection() }) // 接收事件 eventBus.on(selection-change, (payload) { if (payload.tabId ! currentTab.id) { // 处理跨页签逻辑 } })5. 测试验证与异常处理5.1 单元测试要点describe(联动选择测试, () { test(父选触发子选, () { const parent { id: 1, children: [{ childId: 101 }] } handleParentSelect(parent, true) expect(childSelectedKeys.value[1]).toContain(101) }) test(子全选触发父选, () { const parent { id: 1, children: [{ childId: 101 }] } handleChildSelect({ childId: 101 }, true, parent) expect(parentSelectedKeys.value).toContain(1) }) })5.2 常见异常场景数据不一致问题解决方案实现状态校验函数function validateSelection() { return parentSelectedKeys.value.every(parentId { const children getChildren(parentId) return children.every(child (childSelectedKeys.value[parentId] || []).includes(child.childId) ) }) }性能监控指标const perfMetrics { selectTime: 0, updateCount: 0 } function wrapWithPerf(fn) { return (...args) { const start performance.now() const result fn(...args) perfMetrics.selectTime performance.now() - start perfMetrics.updateCount return result } }在项目实际落地过程中我们发现当层级超过5层时需要引入路径压缩算法来优化状态更新性能。通过将树形结构扁平化处理可以使操作时间复杂度从O(n)降低到O(1)。