# useTableColumnControl Hook 使用文档 ## 一、简介 `useTableColumnControl` 是一个用于统一管理表格列显示/隐藏和排序功能的 Vue 3 Composition API Hook。它封装了列配置的加载、保存、同步等逻辑,让开发者只需几行代码即可实现完整的表格列控制功能。 ### 主要功能 - ✅ 列显示/隐藏控制 - ✅ 列排序管理 - ✅ 配置自动保存到本地存储 - ✅ 配置同步到后端服务器 - ✅ 自动加载已保存的配置 - ✅ 类型安全支持 --- ## 二、安装和引入 ### 文件位置 ``` src/hooks/tableColumn.ts ``` ### 引入方式 ```typescript import { useTableColumnControl, type TableColumn } from '/@/hooks/tableColumn'; ``` --- ## 三、基础使用 ### 1. 引入公共样式(推荐) 首先在 ` ``` ### 2. 定义表格列配置 ```typescript import { User, Calendar, Phone } from '@element-plus/icons-vue'; const tableColumns = [ { prop: 'name', label: '姓名', icon: User }, { prop: 'age', label: '年龄', icon: Calendar }, { prop: 'phone', label: '电话', icon: Phone }, ]; ``` ### 3. 使用 Hook ```typescript const { visibleColumns, visibleColumnsSorted, checkColumnVisible, handleColumnChange, handleColumnOrderChange } = useTableColumnControl(tableColumns); ``` ### 4. 在模板中使用 ```vue 筛选条件 数据列表 {{ $index + 1 + ((pagination?.current || 1) - 1) * (pagination?.size || 10) }} {{ col.label }} ``` --- ## 四、完整示例 ```vue {{ $index + 1 + ((state.pagination?.current || 1) - 1) * (state.pagination?.size || 10) }} {{ col.label }} ``` --- ## 五、API 参考 ### TableColumn 类型定义 ```typescript interface TableColumn { prop?: string; // 列属性名 label?: string; // 列标题 icon?: any; // 列图标组件 width?: number | string; // 列宽度 minWidth?: number | string; // 最小宽度 showOverflowTooltip?: boolean; // 是否显示溢出提示 align?: 'left' | 'center' | 'right'; // 对齐方式 alwaysShow?: boolean; // 是否始终显示(不参与列控制) fixed?: boolean | 'left' | 'right'; // 是否固定列 [key: string]: any; // 其他自定义属性 } ``` ### Hook 返回值 | 属性/方法 | 类型 | 说明 | | ------------------------- | ---------------------------- | ---------------------- | | `visibleColumns` | `Ref` | 当前可见的列 key 数组 | | `columnOrder` | `Ref` | 列排序顺序数组 | | `visibleColumnsSorted` | `ComputedRef` | 排序后的可见列配置数组 | | `checkColumnVisible` | `(prop: string) => boolean` | 检查列是否可见 | | `handleColumnChange` | `(value: string[]) => void` | 处理列显示变化 | | `handleColumnOrderChange` | `(order: string[]) => void` | 处理列排序变化 | | `loadSavedConfig` | `() => void` | 手动加载保存的配置 | ### Hook 选项参数 ```typescript interface Options { autoLoad?: boolean; // 是否自动加载配置,默认 true storageKey?: string; // 自定义存储 key,默认使用路由路径 } ``` --- ## 六、高级用法 ### 1. 自定义存储 Key 如果不想使用默认的路由路径作为存储 key,可以自定义: ```typescript const { visibleColumns, visibleColumnsSorted, checkColumnVisible, handleColumnChange, handleColumnOrderChange } = useTableColumnControl( tableColumns, { storageKey: 'custom-table-columns-key', } ); ``` ### 2. 禁用自动加载 如果需要在特定时机手动加载配置: ```typescript const { visibleColumns, visibleColumnsSorted, checkColumnVisible, handleColumnChange, handleColumnOrderChange, loadSavedConfig } = useTableColumnControl(tableColumns, { autoLoad: false, }); // 在需要的时候手动加载 onMounted(() => { loadSavedConfig(); }); ``` ### 3. 固定列和始终显示的列 某些列(如操作列)不应该参与列控制: ```typescript const tableColumns = [ { prop: 'name', label: '姓名', icon: User }, { prop: 'age', label: '年龄', icon: Calendar }, { prop: 'action', label: '操作', alwaysShow: true, // 始终显示 fixed: 'right', // 固定在右侧 }, ]; ``` ### 4. 特殊列模板 如果需要为某些列添加特殊模板: ```vue {{ scope.row.status }} {{ scope.row[col.prop] }} ``` --- ## 七、注意事项 ### 1. 列 Key 的唯一性 确保每列的 `prop` 或 `label` 是唯一的,因为 Hook 使用它们作为标识: ```typescript // ✅ 正确 const tableColumns = [ { prop: 'name', label: '姓名' }, { prop: 'age', label: '年龄' }, ]; // ❌ 错误:两个列都没有 prop const tableColumns = [{ label: '姓名' }, { label: '年龄' }]; ``` ### 2. 响应式更新 `tableColumns` 应该是响应式的,如果需要在运行时动态修改列配置: ```typescript const tableColumns = ref([ { prop: 'name', label: '姓名' }, { prop: 'age', label: '年龄' }, ]); // 动态添加列 tableColumns.value.push({ prop: 'phone', label: '电话' }); ``` ### 3. 配置存储位置 - **本地存储**:使用 `localStorage`,key 为 `user-table-configs-all` - **后端存储**:通过 API 同步,key 为 `user-table-configs` - **页面存储**:每个页面的配置通过路由路径生成唯一 key ### 4. 配置加载时机 Hook 默认在组件挂载时自动加载配置。如果需要在数据加载后重新加载: ```typescript const { loadSavedConfig } = useTableColumnControl(tableColumns); watch( () => someData.value, () => { // 数据变化后重新加载配置 loadSavedConfig(); } ); ``` --- ## 八、扩展方式 ### 1. 添加列宽保存功能 如果需要保存列宽,可以扩展 Hook: ```typescript // 扩展 Hook function useTableColumnControlWithWidth(tableColumns: TableColumn[]) { const baseHook = useTableColumnControl(tableColumns); const columnWidths = ref>({}); const handleColumnWidthChange = (prop: string, width: number) => { columnWidths.value[prop] = width; // 保存到本地存储 const storageKey = getStorageKey(); const config = getTableConfigFromLocal(storageKey) || {}; config.columnWidths = columnWidths.value; saveTableConfigToLocal(storageKey, config); }; return { ...baseHook, columnWidths, handleColumnWidthChange, }; } ``` ### 2. 添加列固定功能 如果需要保存列的固定状态: ```typescript function useTableColumnControlWithFixed(tableColumns: TableColumn[]) { const baseHook = useTableColumnControl(tableColumns); const fixedColumns = ref([]); const toggleColumnFixed = (prop: string) => { const index = fixedColumns.value.indexOf(prop); if (index > -1) { fixedColumns.value.splice(index, 1); } else { fixedColumns.value.push(prop); } // 保存配置 }; return { ...baseHook, fixedColumns, toggleColumnFixed, }; } ``` ### 3. 添加列分组功能 如果需要按分组管理列: ```typescript function useTableColumnControlWithGroup(tableColumns: TableColumn[], groups: Record) { const baseHook = useTableColumnControl(tableColumns); const getColumnsByGroup = (groupName: string) => { return tableColumns.filter((col) => groups[groupName]?.includes(col.prop || '')); }; return { ...baseHook, getColumnsByGroup, }; } ``` ### 4. 自定义存储策略 如果需要使用不同的存储策略(如 IndexedDB): ```typescript function useTableColumnControlWithCustomStorage( tableColumns: TableColumn[], storageAdapter: { get: (key: string) => Promise; set: (key: string, value: any) => Promise; } ) { // 实现自定义存储逻辑 } ``` --- ## 九、常见问题 ### Q1: 为什么配置没有保存? **A:** 检查以下几点: 1. 确保 `handleColumnChange` 和 `handleColumnOrderChange` 已正确绑定到组件 2. 检查浏览器控制台是否有错误 3. 确认 API 调用是否成功(检查网络请求) ### Q2: 为什么某些列无法隐藏? **A:** 检查列配置中是否设置了 `alwaysShow: true` 或 `fixed` 属性: ```typescript // 这些列无法隐藏 { prop: 'action', label: '操作', alwaysShow: true } { prop: 'id', label: 'ID', fixed: 'left' } ``` ### Q3: 如何重置列配置? **A:** 可以手动清除本地存储或调用 API 删除配置: ```typescript // 清除本地存储 localStorage.removeItem('user-table-configs-all'); // 或通过 API 删除 import { deleteUserTableConfig } from '/@/api/admin/usertable'; deleteUserTableConfig(storageKey); ``` ### Q4: 如何在多个页面共享列配置? **A:** 使用相同的 `storageKey`: ```typescript const { visibleColumns } = useTableColumnControl(tableColumns, { storageKey: 'shared-table-columns', }); ``` --- ## 十、最佳实践 ### 1. 列配置管理 将列配置提取到单独的文件中,便于维护: ```typescript // src/views/xxx/columns.ts import { User, Calendar } from '@element-plus/icons-vue'; export const tableColumns = [ { prop: 'name', label: '姓名', icon: User }, { prop: 'age', label: '年龄', icon: Calendar }, ]; ``` ### 2. 类型定义 为列配置添加类型约束: ```typescript import type { TableColumn } from '/@/hooks/tableColumn'; const tableColumns: TableColumn[] = [{ prop: 'name', label: '姓名', icon: User }]; ``` ### 3. 统一命名 保持列 `prop` 与后端字段名一致,便于数据处理。 ### 4. 性能优化 对于大量列的表格,考虑使用虚拟滚动或分页加载列配置。 --- ## 十一、迁移指南 ### 从旧实现迁移到 Hook **旧代码(~90 行):** ```typescript const visibleColumns = ref([]); const columnOrder = ref([]); const loadSavedConfig = () => { /* ... */ }; const handleColumnChange = () => { /* ... */ }; // ... 更多代码 ``` **新代码(~5 行):** ```typescript import { useTableColumnControl } from '/@/hooks/tableColumn'; const { visibleColumns, visibleColumnsSorted, checkColumnVisible, handleColumnChange, handleColumnOrderChange } = useTableColumnControl(tableColumns); ``` ### 迁移步骤 1. 引入 Hook 2. 删除旧的列控制逻辑(`loadSavedConfig`、`handleColumnChange` 等) 3. 使用 Hook 返回值替换原有变量 4. 测试功能是否正常 --- ## 十二、更新日志 ### v1.0.0 (2024-01-XX) - ✅ 初始版本发布 - ✅ 支持列显示/隐藏控制 - ✅ 支持列排序管理 - ✅ 支持本地存储和服务器同步 - ✅ 支持自动加载配置 --- ## 十三、相关资源 - **Hook 源码**:`src/hooks/tableColumn.ts` - **API 接口**:`src/api/admin/usertable.ts` - **组件源码**:`src/components/TableColumnControl/index.vue` - **示例页面**:`src/views/stuwork/classmasterresume/index.vue` --- ## 十四、贡献指南 如果发现 bug 或有改进建议,请: 1. 提交 Issue 描述问题 2. 提交 Pull Request 提供修复方案 3. 更新本文档说明变更 --- **最后更新:2024-01-XX**