From f340c28d11d24d89e16806c3dce663c394ce7f6f Mon Sep 17 00:00:00 2001 From: xuliangzhan Date: Mon, 18 Nov 2024 10:02:00 +0800 Subject: [PATCH] releases 4.9.0 --- README.en.md | 2 +- README.md | 2 +- README.zh-TW.md | 2 +- examples/views/table/TableTest2.vue | 7 +- examples/views/table/TableTest9.vue | 1 - helper/vetur/attributes.json | 2 +- helper/vetur/tags.json | 2 +- package.json | 6 +- packages/table/module/custom/hook.ts | 4 + packages/table/module/edit/hook.ts | 81 +++-- packages/table/module/filter/hook.ts | 5 +- packages/table/module/keyboard/hook.ts | 4 +- packages/table/src/body.ts | 77 ++-- packages/table/src/cell.ts | 232 +++++++----- packages/table/src/emits.ts | 3 + packages/table/src/footer.ts | 341 ++++++++++-------- packages/table/src/header.ts | 273 +++++++++------ packages/table/src/props.ts | 6 +- packages/table/src/table.ts | 467 +++++++++++++++++++------ packages/table/src/util.ts | 10 + packages/ui/index.ts | 11 +- styles/components/table.scss | 77 ++-- 22 files changed, 1027 insertions(+), 588 deletions(-) diff --git a/README.en.md b/README.en.md index c2471cfa68..6aac9f238f 100644 --- a/README.en.md +++ b/README.en.md @@ -12,7 +12,7 @@ [![pull requests closed](https://img.shields.io/github/issues-pr-closed/x-extends/vxe-table.svg)](https://github.com/x-extends/vxe-table/pulls?q=is%3Apr+is%3Aclosed) [![npm license](https://img.shields.io/github/license/mashape/apistatus.svg)](LICENSE) -A [vue](https://www.npmjs.com/package/vue) based PC form component, support add delete change check, virtual tree, column drag and drop, lazy loading, shortcut menu, data verification, import/export/print, form rendering, custom template, renderer, JSON configuration... +A [vue](https://www.npmjs.com/package/vue) based PC form component, support add delete change check, virtual tree, drag and drop, lazy loading, shortcut menu, data verification, import/export/print, form rendering, custom template, renderer, JSON configuration... ## Browser Support diff --git a/README.md b/README.md index d2deef37a3..507a17029f 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ [![pull requests closed](https://img.shields.io/github/issues-pr-closed/x-extends/vxe-table.svg)](https://github.com/x-extends/vxe-table/pulls?q=is%3Apr+is%3Aclosed) [![npm license](https://img.shields.io/github/license/mashape/apistatus.svg)](LICENSE) -一个基于 [vue](https://www.npmjs.com/package/vue) 的 PC 端表单/表格组件,支持增删改查、虚拟树、列拖拽、懒加载、快捷菜单、数据校验、导入/导出/打印、表单渲染、自定义模板、渲染器、JSON 配置式... +一个基于 [vue](https://www.npmjs.com/package/vue) 的 PC 端表单/表格组件,支持增删改查、虚拟树、拖拽排序、懒加载、快捷菜单、数据校验、导入/导出/打印、表单渲染、自定义模板、渲染器、JSON 配置式... * 设计理念 * 面向现代浏览器,高效的简洁 API 设计 diff --git a/README.zh-TW.md b/README.zh-TW.md index 281d7c6463..b86a45db7c 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -12,7 +12,7 @@ [![pull requests closed](https://img.shields.io/github/issues-pr-closed/x-extends/vxe-table.svg)](https://github.com/x-extends/vxe-table/pulls?q=is%3Apr+is%3Aclosed) [![npm license](https://img.shields.io/github/license/mashape/apistatus.svg)](LICENSE) -一個基於 [vue](https://www.npmjs.com/package/vue) 的PC端表格組件,支持增刪改查、虛擬樹、列拖拽、懶加載、快捷菜單、數據校驗、導入/匯出/列印、表單渲染、自定義模板、渲染器、JSON 配置式… +一個基於 [vue](https://www.npmjs.com/package/vue) 的PC端表格組件,支持增刪改查、虛擬樹、拖拽排序、懶加載、快捷菜單、數據校驗、導入/匯出/列印、表單渲染、自定義模板、渲染器、JSON 配置式… ## 瀏覽器支持 diff --git a/examples/views/table/TableTest2.vue b/examples/views/table/TableTest2.vue index 146e8af0bc..43372225f2 100644 --- a/examples/views/table/TableTest2.vue +++ b/examples/views/table/TableTest2.vue @@ -6,12 +6,13 @@ border stripe resizable + show-footer highlight-hover-row height="400" ref="tableRef" id="bbbbb" :row-config="{useKey: true,drag:true}" - :column-config="{useKey: true}" + :column-config="{useKey: true,drag: true}" :custom-config="customConfig" :loading="demo1.loading" :import-config="{modes: importModes}" @@ -19,6 +20,7 @@ :expand-config="{iconOpen: 'vxe-icon-question-circle-fill', iconClose: 'vxe-icon-question-circle-fill'}" :checkbox-config="{labelField: 'id', highlight: true, range: true}" :data="demo1.tableData" + :footer-data="demo1.footerData" @row-dragstart="rowDragstartEvent" @row-dragover="rowDragoverEvent" @row-dragend="rowDragendEvent"> @@ -85,6 +87,9 @@ const customConfig = reactive({ const demo1 = reactive({ loading: false, tableData: [] as any[], + footerData: [ + { role: '777', name: '11', sex11: '22', sex22: '44', name1: '66', sex: '5656', age: '666' } + ], sexList: [ { label: '女', value: '0' }, { label: '男', value: '1' } diff --git a/examples/views/table/TableTest9.vue b/examples/views/table/TableTest9.vue index f87454e3f5..48d6a91422 100644 --- a/examples/views/table/TableTest9.vue +++ b/examples/views/table/TableTest9.vue @@ -10,7 +10,6 @@ :column-config="{resizable: true}" :scroll-x="{enabled: true, gt: 0}" :scroll-y="{enabled: true, gt: 0}" - :checkbox-config="{labelField: 'name', highlight: true, range: true}" :data="tableData"> diff --git a/helper/vetur/attributes.json b/helper/vetur/attributes.json index b0bdbc819f..06c01890e9 100644 --- a/helper/vetur/attributes.json +++ b/helper/vetur/attributes.json @@ -1 +1 @@ -{"vxe-table/id":{"type":"string","description":"唯一标识(被某些特定的功能所依赖)"},"vxe-table/data":{"type":"any[]","description":"表格数据(与 loadData 行为一致,更新数据是不会重置状态)"},"vxe-table/height":{"type":"number | string","description":"表格的高度;支持铺满父容器或者固定高度,如果设置 auto 为铺满父容器(如果设置为 auto,则必须确保存在父节点且不允许存在相邻元素)"},"vxe-table/min-height":{"type":"number | string","description":"表格最小高度"},"vxe-table/max-height":{"type":"number | string","description":"表格的最大高度"},"vxe-table/auto-resize":{"type":"boolean","description":"自动监听父元素的变化去重新计算表格(对于父元素可能存在动态变化、显示隐藏的容器中、列宽异常等场景中的可能会用到)"},"vxe-table/sync-resize":{"type":"boolean | string | number","description":"自动跟随某个属性的变化去重新计算表格,和手动调用 recalculate 方法是一样的效果(对于通过某个属性来控制显示/隐藏切换时可能会用到)"},"vxe-table/resizable":{"type":"boolean","description":"已废弃,被 column-config.resizable 替换"},"vxe-table/stripe":{"type":"boolean","description":"是否带有斑马纹(需要注意的是,在可编辑表格场景下,临时插入的数据不会有斑马纹样式)"},"vxe-table/border":{"type":"boolean | string","description":"是否带有边框"},"vxe-table/padding":{"type":"boolean"},"vxe-table/round":{"type":"boolean","description":"是否为圆角边框"},"vxe-table/size":{"type":"string","description":"表格的尺寸"},"vxe-table/loading":{"type":"boolean","description":"表格是否显示加载中"},"vxe-table/align":{"type":"string","description":"所有的列对齐方式"},"vxe-table/header-align":{"type":"string","description":"所有的表头列的对齐方式"},"vxe-table/footer-align":{"type":"string","description":"所有的表尾列的对齐方式"},"vxe-table/show-header":{"type":"boolean","description":"是否显示表头"},"vxe-table/highlight-current-row":{"type":"boolean","description":"已废弃,被 row-config.isCurrent 替换"},"vxe-table/highlight-hover-row":{"type":"boolean","description":"已废弃,被 row-config.isHover 替换"},"vxe-table/highlight-current-column":{"type":"boolean","description":"已废弃,被 column-config.isCurrent 替换"},"vxe-table/highlight-hover-column":{"type":"boolean","description":"已废弃,被 column-config.isHover 替换"},"vxe-table/row-class-name":{"type":"string | (({ row, rowindex, $rowindex }) => any)","description":"给行附加 className"},"vxe-table/cell-class-name":{"type":"string | (({ row, rowindex, $rowindex, column, columnindex, $columnindex }) => any)","description":"给单元格附加 className"},"vxe-table/header-row-class-name":{"type":"string | (({ $rowindex }) => any)","description":"给表头的行附加 className"},"vxe-table/header-cell-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头的单元格附加 className"},"vxe-table/footer-row-class-name":{"type":"string | (({ $rowindex }) => any)","description":"给表尾的行附加 className"},"vxe-table/footer-cell-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表尾的单元格附加 className"},"vxe-table/cell-style":{"type":"any | (({ row, rowindex, $rowindex, column, columnindex, $columnindex }) => any)","description":"给单元格附加样式"},"vxe-table/header-cell-style":{"type":"any | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头单元格附加样式"},"vxe-table/footer-cell-style":{"type":"any | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表尾单元格附加样式"},"vxe-table/row-style":{"type":"any | (({ row, rowindex, $rowindex }) => any)","description":"给行附加样式,也可以是函数"},"vxe-table/header-row-style":{"type":"any | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头行附加样式"},"vxe-table/footer-row-style":{"type":"any | (({ $rowindex }) => any)","description":"给表尾行附加样式"},"vxe-table/show-footer":{"type":"boolean","description":"是否显示表尾"},"vxe-table/footer-data":{"type":"any[]","description":"表尾数据"},"vxe-table/footer-method":{"type":"({ columns, data }) => any[][]","description":"表尾的数据获取方法,返回一个二维数组"},"vxe-table/merge-cells":{"type":"array<{ row: number, col: number, rowspan: number, colspan: number }>","description":"临时合并指定的单元格 (不能用于展开行,不建议用于固定列、树形结构)"},"vxe-table/merge-footer-items":{"type":"array<{ row: number, col: number, rowspan: number, colspan: number }>","description":"临时合并表尾 (不能用于展开行,不建议用于固定列、树形结构)"},"vxe-table/span-method":{"type":"({ row, rowindex, $rowindex, _rowindex, column, columnindex, $columnindex, _columnindex, data }) => { rowspan: number, colspan: number}","description":"自定义合并函数,返回计算后的值 (不能用于虚拟滚动、展开行,不建议用于固定列、树形结构)"},"vxe-table/footer-span-method":{"type":"({ $rowindex, column, columnindex, $columnindex, _columnindex, data }) => { rowspan: number, colspan: number}","description":"表尾合并行或列,返回计算后的值 (不能用于虚拟滚动、展开行,不建议用于固定列、树形结构)"},"vxe-table/show-overflow":{"type":"boolean | string","description":"设置所有内容过长时显示为省略号(如果是固定列建议设置该值,提升渲染速度)"},"vxe-table/show-header-overflow":{"type":"boolean | string","description":"设置表头所有内容过长时显示为省略号"},"vxe-table/show-footer-overflow":{"type":"boolean | string","description":"设置表尾所有内容过长时显示为省略号"},"vxe-table/column-key":{"type":"boolean","description":"已废弃,被 column-config.useKey 替换"},"vxe-table/row-key":{"type":"boolean","description":"已废弃,被 row-config.useKey 替换"},"vxe-table/row-id":{"type":"string","description":"已废弃,被 row-config.keyField 替换"},"vxe-table/keep-source":{"type":"boolean","description":"保持原始值的状态,被某些功能所依赖,比如编辑状态、还原数据等(开启后影响性能,具体取决于数据量)"},"vxe-table/column-config":{"type":"any","description":"列配置信息"},"vxe-table/cell-config":{"type":"any"},"vxe-table/row-config":{"type":"any","description":"行配置信息"},"vxe-table/resize-config":{"type":"object","description":"响应式布局配置项"},"vxe-table/resizable-config":{"type":"object","description":"列宽拖动配置项"},"vxe-table/seq-config":{"type":"any","description":"序号配置项"},"vxe-table/sort-config":{"type":"any","description":"排序配置项"},"vxe-table/drag-config":{"type":"any","description":"拖拽配置信息"},"vxe-table/filter-config":{"type":"any","description":"筛选配置项"},"vxe-table/export-config":{"type":"any","description":"导出配置项"},"vxe-table/import-config":{"type":"any","description":"导入配置项"},"vxe-table/print-config":{"type":"any","description":"打印配置项"},"vxe-table/radio-config":{"type":"any","description":"单选框配置项"},"vxe-table/checkbox-config":{"type":"any","description":"复选框配置项"},"vxe-table/tooltip-config":{"type":"any","description":"tooltip 配置项"},"vxe-table/expand-config":{"type":"any","description":"展开行配置项(不支持虚拟滚动)"},"vxe-table/tree-config":{"type":"any","description":"树形结构配置项"},"vxe-table/menu-config":{"type":"any","description":"右键菜单配置项"},"vxe-table/clip-config":{"type":"any","description":"复制/粘贴配置项"},"vxe-table/fnr-config":{"type":"any","description":"查找/替换配置项"},"vxe-table/mouse-config":{"type":"any","description":"鼠标配置项"},"vxe-table/area-config":{"type":"any","description":"区域选取配置项"},"vxe-table/keyboard-config":{"type":"any","description":"按键配置项"},"vxe-table/edit-config":{"type":"any","description":"可编辑配置项"},"vxe-table/valid-config":{"type":"any","description":"校验配置项"},"vxe-table/edit-rules":{"type":"{ [field: string]: vxetabledefines.validatorrule[] }","description":"校验规则配置项"},"vxe-table/empty-text":{"type":"string","description":"空数据时显示的内容"},"vxe-table/empty-render":{"type":"any","description":"空内容渲染配置项,empty-render 的优先级大于 empty-text"},"vxe-table/loading-config":{"type":"any","description":"加载中配置项"},"vxe-table/custom-config":{"type":"any","description":"个性化信息配置项"},"vxe-table/scroll-x":{"type":"any","description":"横向虚拟滚动配置(不支持展开行)"},"vxe-table/scroll-y":{"type":"any","description":"纵向虚拟滚动配置(不支持展开行)"},"vxe-table/params":{"type":"any","description":"自定义参数(可以用来存放一些自定义的数据)"},"vxe-colgroup/field":{"type":"string","description":"列字段名(注:属性层级越深,渲染性能就越差,例如:aa.bb.cc.dd.ee)"},"vxe-colgroup/title":{"type":"string","description":"列标题(支持开启国际化)"},"vxe-colgroup/width":{"type":"number | string","description":"列宽度(如果为空则均匀分配剩余宽度,如果全部列固定了,可能会存在宽屏下不会铺满,可以配合 \"%\" 或者 \"min-width\" 布局)"},"vxe-colgroup/min-width":{"type":"number | string","description":"最小列宽度;会自动将剩余空间按比例分配"},"vxe-colgroup/resizable":{"type":"boolean","description":"列是否允许拖动列宽调整大小"},"vxe-colgroup/visible":{"type":"boolean","description":"默认是否显示"},"vxe-colgroup/fixed":{"type":"string","description":"将列固定在左侧或者右侧(注意:固定列应该放在左右两侧的位置)"},"vxe-colgroup/align":{"type":"string","description":"列对齐方式"},"vxe-colgroup/header-align":{"type":"string","description":"表头列的对齐方式"},"vxe-colgroup/show-overflow":{"type":"string | boolean","description":"当内容过长时显示为省略号"},"vxe-colgroup/show-header-overflow":{"type":"string | boolean","description":"当表头内容过长时显示为省略号"},"vxe-colgroup/header-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头的单元格附加 className"},"vxe-column/type":{"type":"string","description":"列的类型(部分功能需要设置 column-config.useKey | row-config.useKey)"},"vxe-column/field":{"type":"string","description":"列字段名(注:属性层级越深,渲染性能就越差,例如:aa.bb.cc.dd.ee)"},"vxe-column/title":{"type":"string","description":"列标题(支持开启国际化)"},"vxe-column/width":{"type":"number | string","description":"列宽度(如果为空则均匀分配剩余宽度,如果全部列固定了,可能会存在宽屏下不会铺满,可以配合 \"%\" 或者 \"min-width\" 布局)"},"vxe-column/min-width":{"type":"number | string","description":"最小列宽度;会自动将剩余空间按比例分配"},"vxe-column/resizable":{"type":"boolean","description":"列是否允许拖动列宽调整大小"},"vxe-column/visible":{"type":"boolean","description":"默认是否显示"},"vxe-column/fixed":{"type":"string","description":"将列固定在左侧或者右侧(注意:固定列应该放在左右两侧的位置)"},"vxe-column/align":{"type":"string","description":"列对齐方式"},"vxe-column/header-align":{"type":"string","description":"表头列的对齐方式"},"vxe-column/footer-align":{"type":"string","description":"表尾列的对齐方式"},"vxe-column/show-overflow":{"type":"string | boolean","description":"当内容过长时显示为省略号"},"vxe-column/show-header-overflow":{"type":"string | boolean","description":"当表头内容过长时显示为省略号"},"vxe-column/show-footer-overflow":{"type":"boolean | string","description":"当表尾内容过长时显示为省略号"},"vxe-column/class-name":{"type":"string | (({row, rowindex, $rowindex, column, columnindex, $columnindex}) => any)","description":"给单元格附加 className"},"vxe-column/header-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头的单元格附加 className"},"vxe-column/footer-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表尾的单元格附加 className"},"vxe-column/formatter":{"type":"(({ cellvalue, row, column }) => string) | any[] | string","description":"格式化显示内容"},"vxe-column/sortable":{"type":"boolean","description":"数据排序,是否允许列排序"},"vxe-column/sort-by":{"type":"string | (({ row, column }) => string | number)","description":"数据排序,只对 sortable 有效,指定排序的字段(当值 formatter 格式化后,可以设置该字段,使用值进行排序)"},"vxe-column/sort-type":{"type":"string","description":"数据排序,排序的字段类型,比如字符串转数值等"},"vxe-column/filters":{"type":"any[]","description":"数据筛选,配置筛选条件(注:筛选只能用于列表,如果是树结构则过滤根节点)"},"vxe-column/filter-multiple":{"type":"boolean","description":"数据筛选,只对 filters 有效,筛选是否允许多选"},"vxe-column/filter-method":{"type":"({ value, option, cellvalue, row, column }) => boolean","description":"数据筛选,只对 filters 有效,列的筛选方法,该方法的返回值用来决定该行是否显示"},"vxe-column/filter-reset-method":{"type":"({ options, column }) => void","description":"数据筛选,只对 filters 有效,自定义筛选重置方法"},"vxe-column/filter-recover-method":{"type":"({ option, column }) => void","description":"数据筛选,只对 filters 有效,自定义筛选复原方法(使用自定义筛选时可能会用到)"},"vxe-column/filter-render":{"type":"any","description":"数据筛选,筛选渲染器配置项"},"vxe-column/header-export-method":{"type":"({ column, options }) => string","description":"自定义表头单元格数据导出方法,返回自定义的标题"},"vxe-column/export-method":{"type":"({ row, column, options }) => string","description":"自定义单元格数据导出方法,返回自定义的值"},"vxe-column/footer-export-method":{"type":"({ items, _columnindex, options }) => string","description":"自定义表尾单元格数据导出方法,返回自定义的值"},"vxe-column/title-help":{"type":"any","description":"即将废弃,请使用 title.prefix"},"vxe-column/title-prefix":{"type":"any","description":"标题前缀图标配置项"},"vxe-column/title-suffix":{"type":"any","description":"标题后缀图标配置项"},"vxe-column/cell-type":{"type":"string","description":"只对特定功能有效,单元格值类型(例如:导出数据类型设置)"},"vxe-column/cell-render":{"type":"any","description":"默认的渲染器配置项"},"vxe-column/edit-render":{"type":"any","description":"可编辑渲染器配置项"},"vxe-column/content-render":{"type":"any","description":"内容渲染配置项"},"vxe-column/tree-node":{"type":"boolean","description":"只对 tree-config 配置时有效,指定为树节点"},"vxe-column/params":{"type":"any","description":"额外的参数(可以用来存放一些私有参数)"},"vxe-column/col-id":{"type":"string | number","description":"自定义列的唯一主键(注:列主键必须确保唯一,操作不正确将导致出现问题)"},"vxe-grid/id":{"type":"string","description":"唯一标识(被某些特定的功能所依赖)"},"vxe-grid/columns":{"type":"array","description":"列配置"},"vxe-grid/data":{"type":"any[]","description":"表格数据(与 loadData 行为一致,更新数据是不会重置状态)"},"vxe-grid/height":{"type":"number | string","description":"表格的高度;支持铺满父容器或者固定高度,如果设置 auto 为铺满父容器(如果设置为 auto,则必须确保存在父节点且不允许存在相邻元素)"},"vxe-grid/min-height":{"type":"number | string","description":"表格最小高度"},"vxe-grid/max-height":{"type":"number | string","description":"表格的最大高度"},"vxe-grid/auto-resize":{"type":"boolean","description":"自动监听父元素的变化去重新计算表格(对于父元素可能存在动态变化、显示隐藏的容器中、列宽异常等场景中的可能会用到)"},"vxe-grid/sync-resize":{"type":"boolean | string | number","description":"自动跟随某个属性的变化去重新计算表格,和手动调用 recalculate 方法是一样的效果(对于通过某个属性来控制显示/隐藏切换时可能会用到)"},"vxe-grid/resizable":{"type":"boolean","description":"已废弃,被 column-config.resizable 替换"},"vxe-grid/stripe":{"type":"boolean","description":"是否带有斑马纹(需要注意的是,在可编辑表格场景下,临时插入的数据不会有斑马纹样式)"},"vxe-grid/border":{"type":"boolean | string","description":"是否带有边框"},"vxe-grid/padding":{"type":"boolean"},"vxe-grid/round":{"type":"boolean","description":"是否为圆角边框"},"vxe-grid/size":{"type":"string","description":"表格的尺寸"},"vxe-grid/loading":{"type":"boolean","description":"表格是否显示加载中"},"vxe-grid/align":{"type":"string","description":"所有的列对齐方式"},"vxe-grid/header-align":{"type":"string","description":"所有的表头列的对齐方式"},"vxe-grid/footer-align":{"type":"string","description":"所有的表尾列的对齐方式"},"vxe-grid/show-header":{"type":"boolean","description":"是否显示表头"},"vxe-grid/highlight-current-row":{"type":"boolean","description":"已废弃,被 row-config.isCurrent 替换"},"vxe-grid/highlight-hover-row":{"type":"boolean","description":"已废弃,被 row-config.isHover 替换"},"vxe-grid/highlight-current-column":{"type":"boolean","description":"已废弃,被 column-config.isCurrent 替换"},"vxe-grid/highlight-hover-column":{"type":"boolean","description":"已废弃,被 column-config.isHover 替换"},"vxe-grid/row-class-name":{"type":"string | (({ row, rowindex, $rowindex }) => any)","description":"给行附加 className"},"vxe-grid/cell-class-name":{"type":"string | (({ row, rowindex, $rowindex, column, columnindex, $columnindex }) => any)","description":"给单元格附加 className"},"vxe-grid/header-row-class-name":{"type":"string | (({ $rowindex }) => any)","description":"给表头的行附加 className"},"vxe-grid/header-cell-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头的单元格附加 className"},"vxe-grid/footer-row-class-name":{"type":"string | (({ $rowindex }) => any)","description":"给表尾的行附加 className"},"vxe-grid/footer-cell-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表尾的单元格附加 className"},"vxe-grid/cell-style":{"type":"any | (({ row, rowindex, $rowindex, column, columnindex, $columnindex }) => any)","description":"给单元格附加样式"},"vxe-grid/header-cell-style":{"type":"any | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头单元格附加样式"},"vxe-grid/footer-cell-style":{"type":"any | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表尾单元格附加样式"},"vxe-grid/row-style":{"type":"any | (({ row, rowindex, $rowindex }) => any)","description":"给行附加样式,也可以是函数"},"vxe-grid/header-row-style":{"type":"any | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头行附加样式"},"vxe-grid/footer-row-style":{"type":"any | (({ $rowindex }) => any)","description":"给表尾行附加样式"},"vxe-grid/show-footer":{"type":"boolean","description":"是否显示表尾"},"vxe-grid/footer-data":{"type":"any[]","description":"表尾数据"},"vxe-grid/footer-method":{"type":"({ columns, data }) => any[][]","description":"表尾的数据获取方法,返回一个二维数组"},"vxe-grid/merge-cells":{"type":"array<{ row: number, col: number, rowspan: number, colspan: number }>","description":"临时合并指定的单元格 (不能用于展开行,不建议用于固定列、树形结构)"},"vxe-grid/merge-footer-items":{"type":"array<{ row: number, col: number, rowspan: number, colspan: number }>","description":"临时合并表尾 (不能用于展开行,不建议用于固定列、树形结构)"},"vxe-grid/span-method":{"type":"({ row, rowindex, $rowindex, _rowindex, column, columnindex, $columnindex, _columnindex, data }) => { rowspan: number, colspan: number}","description":"自定义合并函数,返回计算后的值 (不能用于虚拟滚动、展开行,不建议用于固定列、树形结构)"},"vxe-grid/footer-span-method":{"type":"({ $rowindex, column, columnindex, $columnindex, _columnindex, data }) => { rowspan: number, colspan: number}","description":"表尾合并行或列,返回计算后的值 (不能用于虚拟滚动、展开行,不建议用于固定列、树形结构)"},"vxe-grid/show-overflow":{"type":"boolean | string","description":"设置所有内容过长时显示为省略号(如果是固定列建议设置该值,提升渲染速度)"},"vxe-grid/show-header-overflow":{"type":"boolean | string","description":"设置表头所有内容过长时显示为省略号"},"vxe-grid/show-footer-overflow":{"type":"boolean | string","description":"设置表尾所有内容过长时显示为省略号"},"vxe-grid/column-key":{"type":"boolean","description":"已废弃,被 column-config.useKey 替换"},"vxe-grid/row-key":{"type":"boolean","description":"已废弃,被 row-config.useKey 替换"},"vxe-grid/row-id":{"type":"string","description":"已废弃,被 row-config.keyField 替换"},"vxe-grid/keep-source":{"type":"boolean","description":"保持原始值的状态,被某些功能所依赖,比如编辑状态、还原数据等(开启后影响性能,具体取决于数据量)"},"vxe-grid/column-config":{"type":"any","description":"列配置信息"},"vxe-grid/cell-config":{"type":"any"},"vxe-grid/row-config":{"type":"any","description":"行配置信息"},"vxe-grid/resize-config":{"type":"object","description":"响应式布局配置项"},"vxe-grid/resizable-config":{"type":"object","description":"列宽拖动配置项"},"vxe-grid/seq-config":{"type":"any","description":"序号配置项"},"vxe-grid/sort-config":{"type":"any","description":"排序配置项"},"vxe-grid/drag-config":{"type":"any","description":"拖拽配置信息"},"vxe-grid/filter-config":{"type":"any","description":"筛选配置项"},"vxe-grid/export-config":{"type":"any","description":"导出配置项"},"vxe-grid/import-config":{"type":"any","description":"导入配置项"},"vxe-grid/print-config":{"type":"any","description":"打印配置项"},"vxe-grid/radio-config":{"type":"any","description":"单选框配置项"},"vxe-grid/checkbox-config":{"type":"any","description":"复选框配置项"},"vxe-grid/tooltip-config":{"type":"any","description":"tooltip 配置项"},"vxe-grid/expand-config":{"type":"any","description":"展开行配置项(不支持虚拟滚动)"},"vxe-grid/tree-config":{"type":"any","description":"树形结构配置项"},"vxe-grid/menu-config":{"type":"any","description":"右键菜单配置项"},"vxe-grid/clip-config":{"type":"any","description":"复制/粘贴配置项"},"vxe-grid/fnr-config":{"type":"any","description":"查找/替换配置项"},"vxe-grid/mouse-config":{"type":"any","description":"鼠标配置项"},"vxe-grid/area-config":{"type":"any","description":"区域选取配置项"},"vxe-grid/keyboard-config":{"type":"any","description":"按键配置项"},"vxe-grid/edit-config":{"type":"any","description":"可编辑配置项"},"vxe-grid/valid-config":{"type":"any","description":"校验配置项"},"vxe-grid/edit-rules":{"type":"{ [field: string]: vxetabledefines.validatorrule[] }","description":"校验规则配置项"},"vxe-grid/empty-text":{"type":"string","description":"空数据时显示的内容"},"vxe-grid/empty-render":{"type":"any","description":"空内容渲染配置项,empty-render 的优先级大于 empty-text"},"vxe-grid/loading-config":{"type":"any","description":"加载中配置项"},"vxe-grid/custom-config":{"type":"any","description":"个性化信息配置项"},"vxe-grid/scroll-x":{"type":"any","description":"横向虚拟滚动配置(不支持展开行)"},"vxe-grid/scroll-y":{"type":"any","description":"纵向虚拟滚动配置(不支持展开行)"},"vxe-grid/params":{"type":"any","description":"自定义参数(可以用来存放一些自定义的数据)"},"vxe-grid/form-config":{"type":"any","description":"表单配置项"},"vxe-grid/toolbar-config":{"type":"any","description":"工具栏配置"},"vxe-grid/pager-config":{"type":"any","description":"分页配置项"},"vxe-grid/proxy-config":{"type":"any","description":"数据代理配置项(基于 Promise API)"},"vxe-grid/zoom-config":{"type":"any","description":"缩放配置项"},"vxe-grid/layouts":{"type":"string[]","description":"自定义布局"},"vxe-toolbar/size":{"type":"string","description":"尺寸"},"vxe-toolbar/loading":{"type":"boolean","description":"是否加载中"},"vxe-toolbar/class-name":{"type":"string | (({}) => string)","description":"给工具栏 className"},"vxe-toolbar/import":{"type":"boolean | object","description":"导入按钮配置(需要设置 \"import-config\")"},"vxe-toolbar/export":{"type":"boolean | object","description":"导出按钮配置(需要设置 \"export-config\")"},"vxe-toolbar/print":{"type":"boolean | object","description":"打印按钮配置"},"vxe-toolbar/refresh":{"type":"boolean | object","description":"刷新按钮配置"},"vxe-toolbar/custom":{"type":"boolean | object","description":"自定义列配置"},"vxe-toolbar/buttons":{"type":"any[]","description":"左侧按钮列表"},"vxe-toolbar/tools":{"type":"any[]","description":"右侧工具列表"}} \ No newline at end of file +{"vxe-table/id":{"type":"string","description":"唯一标识(被某些特定的功能所依赖)"},"vxe-table/data":{"type":"any[]","description":"表格数据(与 loadData 行为一致,更新数据是不会重置状态)"},"vxe-table/height":{"type":"number | string","description":"表格的高度;支持铺满父容器或者固定高度,如果设置 auto 为铺满父容器(如果设置为 auto,则必须确保存在父节点且不允许存在相邻元素)"},"vxe-table/min-height":{"type":"number | string","description":"表格最小高度"},"vxe-table/max-height":{"type":"number | string","description":"表格的最大高度"},"vxe-table/auto-resize":{"type":"boolean","description":"自动监听父元素的变化去重新计算表格(对于父元素可能存在动态变化、显示隐藏的容器中、列宽异常等场景中的可能会用到)"},"vxe-table/sync-resize":{"type":"boolean | string | number","description":"自动跟随某个属性的变化去重新计算表格,和手动调用 recalculate 方法是一样的效果(对于通过某个属性来控制显示/隐藏切换时可能会用到)"},"vxe-table/resizable":{"type":"boolean","description":"已废弃,被 column-config.resizable 替换"},"vxe-table/stripe":{"type":"boolean","description":"是否带有斑马纹(需要注意的是,在可编辑表格场景下,临时插入的数据不会有斑马纹样式)"},"vxe-table/border":{"type":"boolean | string","description":"是否带有边框"},"vxe-table/padding":{"type":"boolean"},"vxe-table/round":{"type":"boolean","description":"是否为圆角边框"},"vxe-table/size":{"type":"string","description":"表格的尺寸"},"vxe-table/loading":{"type":"boolean","description":"表格是否显示加载中"},"vxe-table/align":{"type":"string","description":"所有的列对齐方式"},"vxe-table/header-align":{"type":"string","description":"所有的表头列的对齐方式"},"vxe-table/footer-align":{"type":"string","description":"所有的表尾列的对齐方式"},"vxe-table/show-header":{"type":"boolean","description":"是否显示表头"},"vxe-table/highlight-current-row":{"type":"boolean","description":"已废弃,被 row-config.isCurrent 替换"},"vxe-table/highlight-hover-row":{"type":"boolean","description":"已废弃,被 row-config.isHover 替换"},"vxe-table/highlight-current-column":{"type":"boolean","description":"已废弃,被 column-config.isCurrent 替换"},"vxe-table/highlight-hover-column":{"type":"boolean","description":"已废弃,被 column-config.isHover 替换"},"vxe-table/row-class-name":{"type":"string | (({ row, rowindex, $rowindex }) => any)","description":"给行附加 className"},"vxe-table/cell-class-name":{"type":"string | (({ row, rowindex, $rowindex, column, columnindex, $columnindex }) => any)","description":"给单元格附加 className"},"vxe-table/header-row-class-name":{"type":"string | (({ $rowindex }) => any)","description":"给表头的行附加 className"},"vxe-table/header-cell-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头的单元格附加 className"},"vxe-table/footer-row-class-name":{"type":"string | (({ $rowindex }) => any)","description":"给表尾的行附加 className"},"vxe-table/footer-cell-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表尾的单元格附加 className"},"vxe-table/cell-style":{"type":"any | (({ row, rowindex, $rowindex, column, columnindex, $columnindex }) => any)","description":"给单元格附加样式"},"vxe-table/header-cell-style":{"type":"any | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头单元格附加样式"},"vxe-table/footer-cell-style":{"type":"any | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表尾单元格附加样式"},"vxe-table/row-style":{"type":"any | (({ row, rowindex, $rowindex }) => any)","description":"给行附加样式,也可以是函数"},"vxe-table/header-row-style":{"type":"any | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头行附加样式"},"vxe-table/footer-row-style":{"type":"any | (({ $rowindex }) => any)","description":"给表尾行附加样式"},"vxe-table/show-footer":{"type":"boolean","description":"是否显示表尾"},"vxe-table/footer-data":{"type":"any[]","description":"表尾数据"},"vxe-table/footer-method":{"type":"({ columns, data }) => any[][]","description":"表尾的数据获取方法,返回一个二维数组"},"vxe-table/merge-cells":{"type":"array<{ row: number, col: number, rowspan: number, colspan: number }>","description":"临时合并指定的单元格 (不能用于展开行,不建议用于固定列、树形结构)"},"vxe-table/merge-footer-items":{"type":"array<{ row: number, col: number, rowspan: number, colspan: number }>","description":"临时合并表尾 (不能用于展开行,不建议用于固定列、树形结构)"},"vxe-table/span-method":{"type":"({ row, rowindex, $rowindex, _rowindex, column, columnindex, $columnindex, _columnindex, data }) => { rowspan: number, colspan: number}","description":"自定义合并函数,返回计算后的值 (不能用于虚拟滚动、展开行,不建议用于固定列、树形结构)"},"vxe-table/footer-span-method":{"type":"({ $rowindex, column, columnindex, $columnindex, _columnindex, data }) => { rowspan: number, colspan: number}","description":"表尾合并行或列,返回计算后的值 (不能用于虚拟滚动、展开行,不建议用于固定列、树形结构)"},"vxe-table/show-overflow":{"type":"boolean | string","description":"设置所有内容过长时显示为省略号(如果是固定列建议设置该值,提升渲染速度)"},"vxe-table/show-header-overflow":{"type":"boolean | string","description":"设置表头所有内容过长时显示为省略号"},"vxe-table/show-footer-overflow":{"type":"boolean | string","description":"设置表尾所有内容过长时显示为省略号"},"vxe-table/column-key":{"type":"boolean","description":"已废弃,被 column-config.useKey 替换"},"vxe-table/row-key":{"type":"boolean","description":"已废弃,被 row-config.useKey 替换"},"vxe-table/row-id":{"type":"string","description":"已废弃,被 row-config.keyField 替换"},"vxe-table/keep-source":{"type":"boolean","description":"保持原始值的状态,被某些功能所依赖,比如编辑状态、还原数据等(开启后影响性能,具体取决于数据量)"},"vxe-table/column-config":{"type":"any","description":"列配置信息"},"vxe-table/cell-config":{"type":"any"},"vxe-table/row-config":{"type":"any","description":"行配置信息"},"vxe-table/resize-config":{"type":"object","description":"响应式布局配置项"},"vxe-table/resizable-config":{"type":"object","description":"列宽拖动配置项"},"vxe-table/seq-config":{"type":"any","description":"序号配置项"},"vxe-table/sort-config":{"type":"any","description":"排序配置项"},"vxe-table/drag-config":{"type":"any","description":"拖拽配置信息"},"vxe-table/row-drag-config":{"type":"any","description":"行拖拽配置信息"},"vxe-table/column-drag-config":{"type":"any","description":"拖拽配置信息"},"vxe-table/filter-config":{"type":"any","description":"筛选配置项"},"vxe-table/export-config":{"type":"any","description":"导出配置项"},"vxe-table/import-config":{"type":"any","description":"导入配置项"},"vxe-table/print-config":{"type":"any","description":"打印配置项"},"vxe-table/radio-config":{"type":"any","description":"单选框配置项"},"vxe-table/checkbox-config":{"type":"any","description":"复选框配置项"},"vxe-table/tooltip-config":{"type":"any","description":"tooltip 配置项"},"vxe-table/expand-config":{"type":"any","description":"展开行配置项(不支持虚拟滚动)"},"vxe-table/tree-config":{"type":"any","description":"树形结构配置项"},"vxe-table/menu-config":{"type":"any","description":"右键菜单配置项"},"vxe-table/clip-config":{"type":"any","description":"复制/粘贴配置项"},"vxe-table/fnr-config":{"type":"any","description":"查找/替换配置项"},"vxe-table/mouse-config":{"type":"any","description":"鼠标配置项"},"vxe-table/area-config":{"type":"any","description":"区域选取配置项"},"vxe-table/keyboard-config":{"type":"any","description":"按键配置项"},"vxe-table/edit-config":{"type":"any","description":"可编辑配置项"},"vxe-table/valid-config":{"type":"any","description":"校验配置项"},"vxe-table/edit-rules":{"type":"{ [field: string]: vxetabledefines.validatorrule[] }","description":"校验规则配置项"},"vxe-table/empty-text":{"type":"string","description":"空数据时显示的内容"},"vxe-table/empty-render":{"type":"any","description":"空内容渲染配置项,empty-render 的优先级大于 empty-text"},"vxe-table/loading-config":{"type":"any","description":"加载中配置项"},"vxe-table/custom-config":{"type":"any","description":"个性化信息配置项"},"vxe-table/scroll-x":{"type":"any","description":"横向滚动配置"},"vxe-table/scroll-y":{"type":"any","description":"纵向滚动配置"},"vxe-table/params":{"type":"any","description":"自定义参数(可以用来存放一些自定义的数据)"},"vxe-colgroup/field":{"type":"string","description":"列字段名(注:属性层级越深,渲染性能就越差,例如:aa.bb.cc.dd.ee)"},"vxe-colgroup/title":{"type":"string","description":"列标题(支持开启国际化)"},"vxe-colgroup/width":{"type":"number | string","description":"列宽度(如果为空则均匀分配剩余宽度,如果全部列固定了,可能会存在宽屏下不会铺满,可以配合 \"%\" 或者 \"min-width\" 布局)"},"vxe-colgroup/min-width":{"type":"number | string","description":"最小列宽度;会自动将剩余空间按比例分配"},"vxe-colgroup/resizable":{"type":"boolean","description":"列是否允许拖动列宽调整大小"},"vxe-colgroup/visible":{"type":"boolean","description":"默认是否显示"},"vxe-colgroup/fixed":{"type":"string","description":"将列固定在左侧或者右侧(注意:固定列应该放在左右两侧的位置)"},"vxe-colgroup/align":{"type":"string","description":"列对齐方式"},"vxe-colgroup/header-align":{"type":"string","description":"表头列的对齐方式"},"vxe-colgroup/show-overflow":{"type":"string | boolean","description":"当内容过长时显示为省略号"},"vxe-colgroup/show-header-overflow":{"type":"string | boolean","description":"当表头内容过长时显示为省略号"},"vxe-colgroup/header-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头的单元格附加 className"},"vxe-column/type":{"type":"string","description":"列的类型(部分功能需要设置 column-config.useKey | row-config.useKey)"},"vxe-column/field":{"type":"string","description":"列字段名(注:属性层级越深,渲染性能就越差,例如:aa.bb.cc.dd.ee)"},"vxe-column/title":{"type":"string","description":"列标题(支持开启国际化)"},"vxe-column/width":{"type":"number | string","description":"列宽度(如果为空则均匀分配剩余宽度,如果全部列固定了,可能会存在宽屏下不会铺满,可以配合 \"%\" 或者 \"min-width\" 布局)"},"vxe-column/min-width":{"type":"number | string","description":"最小列宽度;会自动将剩余空间按比例分配"},"vxe-column/resizable":{"type":"boolean","description":"列是否允许拖动列宽调整大小"},"vxe-column/visible":{"type":"boolean","description":"默认是否显示"},"vxe-column/fixed":{"type":"string","description":"将列固定在左侧或者右侧(注意:固定列应该放在左右两侧的位置)"},"vxe-column/align":{"type":"string","description":"列对齐方式"},"vxe-column/header-align":{"type":"string","description":"表头列的对齐方式"},"vxe-column/footer-align":{"type":"string","description":"表尾列的对齐方式"},"vxe-column/show-overflow":{"type":"string | boolean","description":"当内容过长时显示为省略号"},"vxe-column/show-header-overflow":{"type":"string | boolean","description":"当表头内容过长时显示为省略号"},"vxe-column/show-footer-overflow":{"type":"boolean | string","description":"当表尾内容过长时显示为省略号"},"vxe-column/class-name":{"type":"string | (({row, rowindex, $rowindex, column, columnindex, $columnindex}) => any)","description":"给单元格附加 className"},"vxe-column/header-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头的单元格附加 className"},"vxe-column/footer-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表尾的单元格附加 className"},"vxe-column/formatter":{"type":"(({ cellvalue, row, column }) => string) | any[] | string","description":"格式化显示内容"},"vxe-column/sortable":{"type":"boolean","description":"数据排序,是否允许列排序"},"vxe-column/sort-by":{"type":"string | (({ row, column }) => string | number)","description":"数据排序,只对 sortable 有效,指定排序的字段(当值 formatter 格式化后,可以设置该字段,使用值进行排序)"},"vxe-column/sort-type":{"type":"string","description":"数据排序,排序的字段类型,比如字符串转数值等"},"vxe-column/filters":{"type":"any[]","description":"数据筛选,配置筛选条件(注:筛选只能用于列表,如果是树结构则过滤根节点)"},"vxe-column/filter-multiple":{"type":"boolean","description":"数据筛选,只对 filters 有效,筛选是否允许多选"},"vxe-column/filter-method":{"type":"({ value, option, cellvalue, row, column }) => boolean","description":"数据筛选,只对 filters 有效,列的筛选方法,该方法的返回值用来决定该行是否显示"},"vxe-column/filter-reset-method":{"type":"({ options, column }) => void","description":"数据筛选,只对 filters 有效,自定义筛选重置方法"},"vxe-column/filter-recover-method":{"type":"({ option, column }) => void","description":"数据筛选,只对 filters 有效,自定义筛选复原方法(使用自定义筛选时可能会用到)"},"vxe-column/filter-render":{"type":"any","description":"数据筛选,筛选渲染器配置项"},"vxe-column/header-export-method":{"type":"({ column, options }) => string","description":"自定义表头单元格数据导出方法,返回自定义的标题"},"vxe-column/export-method":{"type":"({ row, column, options }) => string","description":"自定义单元格数据导出方法,返回自定义的值"},"vxe-column/footer-export-method":{"type":"({ items, _columnindex, options }) => string","description":"自定义表尾单元格数据导出方法,返回自定义的值"},"vxe-column/title-help":{"type":"any","description":"即将废弃,请使用 title.prefix"},"vxe-column/title-prefix":{"type":"any","description":"标题前缀图标配置项"},"vxe-column/title-suffix":{"type":"any","description":"标题后缀图标配置项"},"vxe-column/cell-type":{"type":"string","description":"只对特定功能有效,单元格值类型(例如:导出数据类型设置)"},"vxe-column/cell-render":{"type":"any","description":"默认的渲染器配置项"},"vxe-column/edit-render":{"type":"any","description":"可编辑渲染器配置项"},"vxe-column/content-render":{"type":"any","description":"内容渲染配置项"},"vxe-column/tree-node":{"type":"boolean","description":"只对 tree-config 配置时有效,指定为树节点"},"vxe-column/params":{"type":"any","description":"额外的参数(可以用来存放一些私有参数)"},"vxe-column/col-id":{"type":"string | number","description":"自定义列的唯一主键(注:列主键必须确保唯一,操作不正确将导致出现问题)"},"vxe-grid/id":{"type":"string","description":"唯一标识(被某些特定的功能所依赖)"},"vxe-grid/columns":{"type":"array","description":"列配置"},"vxe-grid/data":{"type":"any[]","description":"表格数据(与 loadData 行为一致,更新数据是不会重置状态)"},"vxe-grid/height":{"type":"number | string","description":"表格的高度;支持铺满父容器或者固定高度,如果设置 auto 为铺满父容器(如果设置为 auto,则必须确保存在父节点且不允许存在相邻元素)"},"vxe-grid/min-height":{"type":"number | string","description":"表格最小高度"},"vxe-grid/max-height":{"type":"number | string","description":"表格的最大高度"},"vxe-grid/auto-resize":{"type":"boolean","description":"自动监听父元素的变化去重新计算表格(对于父元素可能存在动态变化、显示隐藏的容器中、列宽异常等场景中的可能会用到)"},"vxe-grid/sync-resize":{"type":"boolean | string | number","description":"自动跟随某个属性的变化去重新计算表格,和手动调用 recalculate 方法是一样的效果(对于通过某个属性来控制显示/隐藏切换时可能会用到)"},"vxe-grid/resizable":{"type":"boolean","description":"已废弃,被 column-config.resizable 替换"},"vxe-grid/stripe":{"type":"boolean","description":"是否带有斑马纹(需要注意的是,在可编辑表格场景下,临时插入的数据不会有斑马纹样式)"},"vxe-grid/border":{"type":"boolean | string","description":"是否带有边框"},"vxe-grid/padding":{"type":"boolean"},"vxe-grid/round":{"type":"boolean","description":"是否为圆角边框"},"vxe-grid/size":{"type":"string","description":"表格的尺寸"},"vxe-grid/loading":{"type":"boolean","description":"表格是否显示加载中"},"vxe-grid/align":{"type":"string","description":"所有的列对齐方式"},"vxe-grid/header-align":{"type":"string","description":"所有的表头列的对齐方式"},"vxe-grid/footer-align":{"type":"string","description":"所有的表尾列的对齐方式"},"vxe-grid/show-header":{"type":"boolean","description":"是否显示表头"},"vxe-grid/highlight-current-row":{"type":"boolean","description":"已废弃,被 row-config.isCurrent 替换"},"vxe-grid/highlight-hover-row":{"type":"boolean","description":"已废弃,被 row-config.isHover 替换"},"vxe-grid/highlight-current-column":{"type":"boolean","description":"已废弃,被 column-config.isCurrent 替换"},"vxe-grid/highlight-hover-column":{"type":"boolean","description":"已废弃,被 column-config.isHover 替换"},"vxe-grid/row-class-name":{"type":"string | (({ row, rowindex, $rowindex }) => any)","description":"给行附加 className"},"vxe-grid/cell-class-name":{"type":"string | (({ row, rowindex, $rowindex, column, columnindex, $columnindex }) => any)","description":"给单元格附加 className"},"vxe-grid/header-row-class-name":{"type":"string | (({ $rowindex }) => any)","description":"给表头的行附加 className"},"vxe-grid/header-cell-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头的单元格附加 className"},"vxe-grid/footer-row-class-name":{"type":"string | (({ $rowindex }) => any)","description":"给表尾的行附加 className"},"vxe-grid/footer-cell-class-name":{"type":"string | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表尾的单元格附加 className"},"vxe-grid/cell-style":{"type":"any | (({ row, rowindex, $rowindex, column, columnindex, $columnindex }) => any)","description":"给单元格附加样式"},"vxe-grid/header-cell-style":{"type":"any | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头单元格附加样式"},"vxe-grid/footer-cell-style":{"type":"any | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表尾单元格附加样式"},"vxe-grid/row-style":{"type":"any | (({ row, rowindex, $rowindex }) => any)","description":"给行附加样式,也可以是函数"},"vxe-grid/header-row-style":{"type":"any | (({ $rowindex, column, columnindex, $columnindex }) => any)","description":"给表头行附加样式"},"vxe-grid/footer-row-style":{"type":"any | (({ $rowindex }) => any)","description":"给表尾行附加样式"},"vxe-grid/show-footer":{"type":"boolean","description":"是否显示表尾"},"vxe-grid/footer-data":{"type":"any[]","description":"表尾数据"},"vxe-grid/footer-method":{"type":"({ columns, data }) => any[][]","description":"表尾的数据获取方法,返回一个二维数组"},"vxe-grid/merge-cells":{"type":"array<{ row: number, col: number, rowspan: number, colspan: number }>","description":"临时合并指定的单元格 (不能用于展开行,不建议用于固定列、树形结构)"},"vxe-grid/merge-footer-items":{"type":"array<{ row: number, col: number, rowspan: number, colspan: number }>","description":"临时合并表尾 (不能用于展开行,不建议用于固定列、树形结构)"},"vxe-grid/span-method":{"type":"({ row, rowindex, $rowindex, _rowindex, column, columnindex, $columnindex, _columnindex, data }) => { rowspan: number, colspan: number}","description":"自定义合并函数,返回计算后的值 (不能用于虚拟滚动、展开行,不建议用于固定列、树形结构)"},"vxe-grid/footer-span-method":{"type":"({ $rowindex, column, columnindex, $columnindex, _columnindex, data }) => { rowspan: number, colspan: number}","description":"表尾合并行或列,返回计算后的值 (不能用于虚拟滚动、展开行,不建议用于固定列、树形结构)"},"vxe-grid/show-overflow":{"type":"boolean | string","description":"设置所有内容过长时显示为省略号(如果是固定列建议设置该值,提升渲染速度)"},"vxe-grid/show-header-overflow":{"type":"boolean | string","description":"设置表头所有内容过长时显示为省略号"},"vxe-grid/show-footer-overflow":{"type":"boolean | string","description":"设置表尾所有内容过长时显示为省略号"},"vxe-grid/column-key":{"type":"boolean","description":"已废弃,被 column-config.useKey 替换"},"vxe-grid/row-key":{"type":"boolean","description":"已废弃,被 row-config.useKey 替换"},"vxe-grid/row-id":{"type":"string","description":"已废弃,被 row-config.keyField 替换"},"vxe-grid/keep-source":{"type":"boolean","description":"保持原始值的状态,被某些功能所依赖,比如编辑状态、还原数据等(开启后影响性能,具体取决于数据量)"},"vxe-grid/column-config":{"type":"any","description":"列配置信息"},"vxe-grid/cell-config":{"type":"any"},"vxe-grid/row-config":{"type":"any","description":"行配置信息"},"vxe-grid/resize-config":{"type":"object","description":"响应式布局配置项"},"vxe-grid/resizable-config":{"type":"object","description":"列宽拖动配置项"},"vxe-grid/seq-config":{"type":"any","description":"序号配置项"},"vxe-grid/sort-config":{"type":"any","description":"排序配置项"},"vxe-grid/drag-config":{"type":"any","description":"拖拽配置信息"},"vxe-grid/row-drag-config":{"type":"any","description":"行拖拽配置信息"},"vxe-grid/column-drag-config":{"type":"any","description":"拖拽配置信息"},"vxe-grid/filter-config":{"type":"any","description":"筛选配置项"},"vxe-grid/export-config":{"type":"any","description":"导出配置项"},"vxe-grid/import-config":{"type":"any","description":"导入配置项"},"vxe-grid/print-config":{"type":"any","description":"打印配置项"},"vxe-grid/radio-config":{"type":"any","description":"单选框配置项"},"vxe-grid/checkbox-config":{"type":"any","description":"复选框配置项"},"vxe-grid/tooltip-config":{"type":"any","description":"tooltip 配置项"},"vxe-grid/expand-config":{"type":"any","description":"展开行配置项(不支持虚拟滚动)"},"vxe-grid/tree-config":{"type":"any","description":"树形结构配置项"},"vxe-grid/menu-config":{"type":"any","description":"右键菜单配置项"},"vxe-grid/clip-config":{"type":"any","description":"复制/粘贴配置项"},"vxe-grid/fnr-config":{"type":"any","description":"查找/替换配置项"},"vxe-grid/mouse-config":{"type":"any","description":"鼠标配置项"},"vxe-grid/area-config":{"type":"any","description":"区域选取配置项"},"vxe-grid/keyboard-config":{"type":"any","description":"按键配置项"},"vxe-grid/edit-config":{"type":"any","description":"可编辑配置项"},"vxe-grid/valid-config":{"type":"any","description":"校验配置项"},"vxe-grid/edit-rules":{"type":"{ [field: string]: vxetabledefines.validatorrule[] }","description":"校验规则配置项"},"vxe-grid/empty-text":{"type":"string","description":"空数据时显示的内容"},"vxe-grid/empty-render":{"type":"any","description":"空内容渲染配置项,empty-render 的优先级大于 empty-text"},"vxe-grid/loading-config":{"type":"any","description":"加载中配置项"},"vxe-grid/custom-config":{"type":"any","description":"个性化信息配置项"},"vxe-grid/scroll-x":{"type":"any","description":"横向滚动配置"},"vxe-grid/scroll-y":{"type":"any","description":"纵向滚动配置"},"vxe-grid/params":{"type":"any","description":"自定义参数(可以用来存放一些自定义的数据)"},"vxe-grid/form-config":{"type":"any","description":"表单配置项"},"vxe-grid/toolbar-config":{"type":"any","description":"工具栏配置"},"vxe-grid/pager-config":{"type":"any","description":"分页配置项"},"vxe-grid/proxy-config":{"type":"any","description":"数据代理配置项(基于 Promise API)"},"vxe-grid/zoom-config":{"type":"any","description":"缩放配置项"},"vxe-grid/layouts":{"type":"string[]","description":"自定义布局"},"vxe-toolbar/size":{"type":"string","description":"尺寸"},"vxe-toolbar/loading":{"type":"boolean","description":"是否加载中"},"vxe-toolbar/class-name":{"type":"string | (({}) => string)","description":"给工具栏 className"},"vxe-toolbar/import":{"type":"boolean | object","description":"导入按钮配置(需要设置 \"import-config\")"},"vxe-toolbar/export":{"type":"boolean | object","description":"导出按钮配置(需要设置 \"export-config\")"},"vxe-toolbar/print":{"type":"boolean | object","description":"打印按钮配置"},"vxe-toolbar/refresh":{"type":"boolean | object","description":"刷新按钮配置"},"vxe-toolbar/custom":{"type":"boolean | object","description":"自定义列配置"},"vxe-toolbar/buttons":{"type":"any[]","description":"左侧按钮列表"},"vxe-toolbar/tools":{"type":"any[]","description":"右侧工具列表"}} \ No newline at end of file diff --git a/helper/vetur/tags.json b/helper/vetur/tags.json index 95fe0e4945..d683746e60 100644 --- a/helper/vetur/tags.json +++ b/helper/vetur/tags.json @@ -1 +1 @@ -{"vxe-table":{"attributes":["id","data","height","min-height","max-height","auto-resize","sync-resize","resizable","stripe","border","padding","round","size","loading","align","header-align","footer-align","show-header","highlight-current-row","highlight-hover-row","highlight-current-column","highlight-hover-column","row-class-name","cell-class-name","header-row-class-name","header-cell-class-name","footer-row-class-name","footer-cell-class-name","cell-style","header-cell-style","footer-cell-style","row-style","header-row-style","footer-row-style","show-footer","footer-data","footer-method","merge-cells","merge-footer-items","span-method","footer-span-method","show-overflow","show-header-overflow","show-footer-overflow","column-key","row-key","row-id","keep-source","column-config","cell-config","row-config","resize-config","resizable-config","seq-config","sort-config","drag-config","filter-config","export-config","import-config","print-config","radio-config","checkbox-config","tooltip-config","expand-config","tree-config","menu-config","clip-config","fnr-config","mouse-config","area-config","keyboard-config","edit-config","valid-config","edit-rules","empty-text","empty-render","loading-config","custom-config","scroll-x","scroll-y","params"],"subtags":["vxe-colgroup","vxe-column"],"description":"基础表格"},"vxe-colgroup":{"attributes":["field","title","width","min-width","resizable","visible","fixed","align","header-align","show-overflow","show-header-overflow","header-class-name"],"subtags":["vxe-column"],"description":"基础表格 - 分组列"},"vxe-column":{"attributes":["type","field","title","width","min-width","resizable","visible","fixed","align","header-align","footer-align","show-overflow","show-header-overflow","show-footer-overflow","class-name","header-class-name","footer-class-name","formatter","sortable","sort-by","sort-type","filters","filter-multiple","filter-method","filter-reset-method","filter-recover-method","filter-render","header-export-method","export-method","footer-export-method","title-help","title-prefix","title-suffix","cell-type","cell-render","edit-render","content-render","tree-node","params","col-id"],"description":"基础表格 - 列"},"vxe-grid":{"attributes":["id","columns","data","height","min-height","max-height","auto-resize","sync-resize","resizable","stripe","border","padding","round","size","loading","align","header-align","footer-align","show-header","highlight-current-row","highlight-hover-row","highlight-current-column","highlight-hover-column","row-class-name","cell-class-name","header-row-class-name","header-cell-class-name","footer-row-class-name","footer-cell-class-name","cell-style","header-cell-style","footer-cell-style","row-style","header-row-style","footer-row-style","show-footer","footer-data","footer-method","merge-cells","merge-footer-items","span-method","footer-span-method","show-overflow","show-header-overflow","show-footer-overflow","column-key","row-key","row-id","keep-source","column-config","cell-config","row-config","resize-config","resizable-config","seq-config","sort-config","drag-config","filter-config","export-config","import-config","print-config","radio-config","checkbox-config","tooltip-config","expand-config","tree-config","menu-config","clip-config","fnr-config","mouse-config","area-config","keyboard-config","edit-config","valid-config","edit-rules","empty-text","empty-render","loading-config","custom-config","scroll-x","scroll-y","params","form-config","toolbar-config","pager-config","proxy-config","zoom-config","layouts"],"description":"配置式表格"},"vxe-toolbar":{"attributes":["size","loading","class-name","import","export","print","refresh","custom","buttons","tools"],"description":"工具栏"}} \ No newline at end of file +{"vxe-table":{"attributes":["id","data","height","min-height","max-height","auto-resize","sync-resize","resizable","stripe","border","padding","round","size","loading","align","header-align","footer-align","show-header","highlight-current-row","highlight-hover-row","highlight-current-column","highlight-hover-column","row-class-name","cell-class-name","header-row-class-name","header-cell-class-name","footer-row-class-name","footer-cell-class-name","cell-style","header-cell-style","footer-cell-style","row-style","header-row-style","footer-row-style","show-footer","footer-data","footer-method","merge-cells","merge-footer-items","span-method","footer-span-method","show-overflow","show-header-overflow","show-footer-overflow","column-key","row-key","row-id","keep-source","column-config","cell-config","row-config","resize-config","resizable-config","seq-config","sort-config","drag-config","row-drag-config","column-drag-config","filter-config","export-config","import-config","print-config","radio-config","checkbox-config","tooltip-config","expand-config","tree-config","menu-config","clip-config","fnr-config","mouse-config","area-config","keyboard-config","edit-config","valid-config","edit-rules","empty-text","empty-render","loading-config","custom-config","scroll-x","scroll-y","params"],"subtags":["vxe-colgroup","vxe-column"],"description":"基础表格"},"vxe-colgroup":{"attributes":["field","title","width","min-width","resizable","visible","fixed","align","header-align","show-overflow","show-header-overflow","header-class-name"],"subtags":["vxe-column"],"description":"基础表格 - 分组列"},"vxe-column":{"attributes":["type","field","title","width","min-width","resizable","visible","fixed","align","header-align","footer-align","show-overflow","show-header-overflow","show-footer-overflow","class-name","header-class-name","footer-class-name","formatter","sortable","sort-by","sort-type","filters","filter-multiple","filter-method","filter-reset-method","filter-recover-method","filter-render","header-export-method","export-method","footer-export-method","title-help","title-prefix","title-suffix","cell-type","cell-render","edit-render","content-render","tree-node","params","col-id"],"description":"基础表格 - 列"},"vxe-grid":{"attributes":["id","columns","data","height","min-height","max-height","auto-resize","sync-resize","resizable","stripe","border","padding","round","size","loading","align","header-align","footer-align","show-header","highlight-current-row","highlight-hover-row","highlight-current-column","highlight-hover-column","row-class-name","cell-class-name","header-row-class-name","header-cell-class-name","footer-row-class-name","footer-cell-class-name","cell-style","header-cell-style","footer-cell-style","row-style","header-row-style","footer-row-style","show-footer","footer-data","footer-method","merge-cells","merge-footer-items","span-method","footer-span-method","show-overflow","show-header-overflow","show-footer-overflow","column-key","row-key","row-id","keep-source","column-config","cell-config","row-config","resize-config","resizable-config","seq-config","sort-config","drag-config","row-drag-config","column-drag-config","filter-config","export-config","import-config","print-config","radio-config","checkbox-config","tooltip-config","expand-config","tree-config","menu-config","clip-config","fnr-config","mouse-config","area-config","keyboard-config","edit-config","valid-config","edit-rules","empty-text","empty-render","loading-config","custom-config","scroll-x","scroll-y","params","form-config","toolbar-config","pager-config","proxy-config","zoom-config","layouts"],"description":"配置式表格"},"vxe-toolbar":{"attributes":["size","loading","class-name","import","export","print","refresh","custom","buttons","tools"],"description":"工具栏"}} \ No newline at end of file diff --git a/package.json b/package.json index d509dd7089..10ebcf4629 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vxe-table", - "version": "4.8.16", - "description": "一个基于 vue 的 PC 端表格组件,支持增删改查、虚拟树、列拖拽,懒加载、快捷菜单、数据校验、树形结构、打印、导入导出、自定义模板、渲染器、JSON 配置式...", + "version": "4.9.0", + "description": "一个基于 vue 的 PC 端表格组件,支持增删改查、虚拟树、拖拽排序,懒加载、快捷菜单、数据校验、树形结构、打印、导入导出、自定义模板、渲染器、JSON 配置式...", "scripts": { "update": "npm install --legacy-peer-deps", "serve": "vue-cli-service serve", @@ -28,7 +28,7 @@ "style": "lib/style.css", "typings": "types/index.d.ts", "dependencies": { - "vxe-pc-ui": "^4.2.54" + "vxe-pc-ui": "^4.3.0" }, "devDependencies": { "@types/resize-observer-browser": "^0.1.11", diff --git a/packages/table/module/custom/hook.ts b/packages/table/module/custom/hook.ts index 704f89d512..8e57c987ee 100644 --- a/packages/table/module/custom/hook.ts +++ b/packages/table/module/custom/hook.ts @@ -92,6 +92,10 @@ VxeUI.hooks.add('tableCustomModule', { column.visible = column.renderVisible } }) + reactData.isDragColMove = true + setTimeout(() => { + reactData.isDragColMove = false + }, 1000) return $xeTable.saveCustomStore('confirm') } diff --git a/packages/table/module/edit/hook.ts b/packages/table/module/edit/hook.ts index 97f1d8061c..73ceb4e12f 100644 --- a/packages/table/module/edit/hook.ts +++ b/packages/table/module/edit/hook.ts @@ -256,6 +256,41 @@ hooks.add('tableEditModule', { }) } + const handleClearEdit = (evnt: Event | null, targetRow?: any) => { + const { editStore } = reactData + const { actived, focused } = editStore + const { row, column } = actived + const validOpts = computeValidOpts.value + if (row || column) { + if (targetRow && getRowid($xeTable, targetRow) !== getRowid($xeTable, row)) { + return nextTick() + } + syncActivedCell() + actived.args = null + actived.row = null + actived.column = null + $xeTable.updateFooter() + $xeTable.dispatchEvent('edit-closed', { + row, + rowIndex: $xeTable.getRowIndex(row), + $rowIndex: $xeTable.getVMRowIndex(row), + column, + columnIndex: $xeTable.getColumnIndex(column), + $columnIndex: $xeTable.getVMColumnIndex(column) + }, evnt || null) + } + if (validOpts.autoClear) { + if (validOpts.msgMode !== 'full' || getConfig().cellVaildMode === 'obsolete') { + if ($xeTable.clearValidate) { + return $xeTable.clearValidate() + } + } + } + focused.row = null + focused.column = null + return nextTick() + } + editMethods = { /** * 往表格中插入临时数据 @@ -514,46 +549,18 @@ hooks.add('tableEditModule', { } return null }, - clearActived (evnt) { + clearActived (row) { // 即将废弃 if (process.env.VUE_APP_VXE_ENV === 'development') { warnLog('vxe.error.delFunc', ['clearActived', 'clearEdit']) } - return this.clearEdit(evnt) + return this.clearEdit(row) }, /** * 清除激活的编辑 */ - clearEdit (evnt) { - const { editStore } = reactData - const { actived, focused } = editStore - const { row, column } = actived - const validOpts = computeValidOpts.value - if (row || column) { - syncActivedCell() - actived.args = null - actived.row = null - actived.column = null - $xeTable.updateFooter() - $xeTable.dispatchEvent('edit-closed', { - row, - rowIndex: $xeTable.getRowIndex(row), - $rowIndex: $xeTable.getVMRowIndex(row), - column, - columnIndex: $xeTable.getColumnIndex(column), - $columnIndex: $xeTable.getVMColumnIndex(column) - }, evnt || null) - } - if (validOpts.autoClear) { - if (validOpts.msgMode !== 'full' || getConfig().cellVaildMode === 'obsolete') { - if ($xeTable.clearValidate) { - return $xeTable.clearValidate() - } - } - } - focused.row = null - focused.column = null - return nextTick() + clearEdit (row) { + return handleClearEdit(null, row) }, /** * 清除所选中源状态 @@ -687,7 +694,7 @@ hooks.add('tableEditModule', { } $xeTable.closeTooltip() if (actived.column) { - editMethods.clearEdit(evnt) + handleClearEdit(evnt) } type = 'edit-activated' column.renderHeight = cell.offsetHeight @@ -765,6 +772,12 @@ hooks.add('tableEditModule', { handleActived (params, evnt) { return editPrivateMethods.handleEdit(params, evnt) }, + /** + * 处理取消编辑 + * @param evnt + * @returns + */ + handleClearEdit, /** * 处理聚焦 */ @@ -836,7 +849,7 @@ hooks.add('tableEditModule', { const selectMethod = () => { if (isMouseSelected && (selected.row !== row || selected.column !== column)) { if (actived.row !== row || (editOpts.mode === 'cell' ? actived.column !== column : false)) { - editMethods.clearEdit(evnt) + handleClearEdit(evnt) editMethods.clearSelected() if ($xeTable.clearCellAreas) { $xeTable.clearCellAreas() diff --git a/packages/table/module/filter/hook.ts b/packages/table/module/filter/hook.ts index e8c23548f0..486d846db7 100644 --- a/packages/table/module/filter/hook.ts +++ b/packages/table/module/filter/hook.ts @@ -1,7 +1,7 @@ import { nextTick } from 'vue' import XEUtils from 'xe-utils' import { VxeUI } from '../../../ui' -import { toFilters, handleFieldOrColumn } from '../../src/util' +import { toFilters, handleFieldOrColumn, getRefElem } from '../../src/util' import { getDomNode, triggerEvent } from '../../../ui/src/dom' import { isEnableConf } from '../../../ui/src/utils' @@ -251,8 +251,7 @@ hooks.add('tableFilterModule', { const { elemStore } = internalData const { fixed } = column return $xeTable.scrollToColumn(column).then(() => { - const headerWrapperRef = elemStore[`${fixed || 'main'}-header-wrapper`] || elemStore['main-header-wrapper'] - const headerWrapperElem = headerWrapperRef ? headerWrapperRef.value : null + const headerWrapperElem = getRefElem(elemStore[`${fixed || 'main'}-header-wrapper`] || elemStore['main-header-wrapper']) if (headerWrapperElem) { const filterBtnElem = headerWrapperElem.querySelector(`.vxe-header--column.${column.id} .vxe-filter--btn`) as HTMLElement triggerEvent(filterBtnElem, 'click') diff --git a/packages/table/module/keyboard/hook.ts b/packages/table/module/keyboard/hook.ts index cf905756ef..ccb590b528 100644 --- a/packages/table/module/keyboard/hook.ts +++ b/packages/table/module/keyboard/hook.ts @@ -1,5 +1,6 @@ import XEUtils from 'xe-utils' import { VxeUI } from '../../../ui' +import { getRefElem } from '../../src/util' import { browse, hasClass, getAbsolutePos, addClass, removeClass, getEventTargetNode } from '../../../ui/src/dom' import type { TableKeyboardPrivateMethods } from '../../../../types' @@ -79,8 +80,7 @@ hooks.add('tableKeyboardModule', { const { elemStore } = internalData const disX = evnt.clientX const disY = evnt.clientY - const bodyWrapperRef = elemStore[`${column.fixed || 'main'}-body-wrapper`] || elemStore['main-body-wrapper'] - const bodyWrapperElem = bodyWrapperRef ? bodyWrapperRef.value : null + const bodyWrapperElem = getRefElem(elemStore[`${column.fixed || 'main'}-body-wrapper`] || elemStore['main-body-wrapper']) if (!bodyWrapperElem) { return } diff --git a/packages/table/src/body.ts b/packages/table/src/body.ts index 983dd6812a..b22b5616b9 100644 --- a/packages/table/src/body.ts +++ b/packages/table/src/body.ts @@ -1,7 +1,7 @@ import { createCommentVNode, defineComponent, TransitionGroup, h, ref, Ref, PropType, inject, nextTick, ComputedRef, onBeforeUnmount, onMounted, onUnmounted } from 'vue' import XEUtils from 'xe-utils' import { VxeUI } from '../../ui' -import { mergeBodyMethod, getRowid, XEBodyScrollElement } from './util' +import { mergeBodyMethod, getRowid, XEBodyScrollElement, getRefElem } from './util' import { updateCellTitle, getPropClass, setScrollTop, setScrollLeft } from '../../ui/src/dom' import { isEnableConf } from '../../ui/src/utils' import { getSlotVNs } from '../../ui/src/vn' @@ -359,7 +359,7 @@ export default defineComponent({ getPropClass(className, params), getPropClass(allCellClassName, params) ], - key: columnKey || columnOpts.useKey || rowOpts.useKey ? colid : $columnIndex, + key: columnKey || columnOpts.useKey || rowOpts.useKey || columnOpts.drag ? colid : $columnIndex, ...attrs, style: Object.assign({ height: cellHeight @@ -370,13 +370,14 @@ export default defineComponent({ const renderRows = (fixedType: any, tableData: any, tableColumn: any) => { const { stripe, rowKey, highlightHoverRow, rowClassName, rowStyle, showOverflow: allColumnOverflow, editConfig, treeConfig } = tableProps - const { hasFixedColumn, treeExpandedMaps, scrollYLoad, rowExpandedMaps, expandColumn, selectRadioRow, pendingRowMaps, pendingRowList } = tableReactData + const { hasFixedColumn, treeExpandedMaps, scrollYLoad, rowExpandedMaps, expandColumn, selectRadioRow, pendingRowMaps, pendingRowList, isDragColMove } = tableReactData const { fullAllDataRowIdData } = tableInternalData const checkboxOpts = computeCheckboxOpts.value const radioOpts = computeRadioOpts.value const treeOpts = computeTreeOpts.value const editOpts = computeEditOpts.value const rowOpts = computeRowOpts.value + const columnOpts = computeColumnOpts.value const { transform } = treeOpts const childrenField = treeOpts.children || treeOpts.childrenField const rows: any[] = [] @@ -431,30 +432,44 @@ export default defineComponent({ rowChildren = row[childrenField] isExpandTree = rowChildren && rowChildren.length > 0 && !!treeExpandedMaps[rowid] } + const trClass = [ + 'vxe-body--row', + treeConfig ? `row--level-${rowLevel}` : '', + { + 'row--stripe': stripe && ($xeTable.getVTRowIndex(row) + 1) % 2 === 0, + 'is--new': isNewRow, + 'is--expand-row': isExpandRow, + 'is--expand-tree': isExpandTree, + 'row--new': isNewRow && (editOpts.showStatus || editOpts.showInsertStatus), + 'row--radio': radioOpts.highlight && $xeTable.eqRow(selectRadioRow, row), + 'row--checked': checkboxOpts.highlight && $xeTable.isCheckedByCheckboxRow(row), + 'row--pending': pendingRowList.length && !!pendingRowMaps[rowid] + }, + getPropClass(rowClassName, params) + ] + const tdVNs = tableColumn.map((column: any, $columnIndex: any) => { + return renderColumn(seq, rowid, fixedType, rowLevel, row, rowIndex, $rowIndex, _rowIndex, column, $columnIndex, tableColumn, tableData) + }) rows.push( - h('tr', { - class: [ - 'vxe-body--row', - treeConfig ? `row--level-${rowLevel}` : '', - { - 'row--stripe': stripe && ($xeTable.getVTRowIndex(row) + 1) % 2 === 0, - 'is--new': isNewRow, - 'is--expand-row': isExpandRow, - 'is--expand-tree': isExpandTree, - 'row--new': isNewRow && (editOpts.showStatus || editOpts.showInsertStatus), - 'row--radio': radioOpts.highlight && $xeTable.eqRow(selectRadioRow, row), - 'row--checked': checkboxOpts.highlight && $xeTable.isCheckedByCheckboxRow(row), - 'row--pending': pendingRowList.length && !!pendingRowMaps[rowid] - }, - getPropClass(rowClassName, params) - ], - rowid: rowid, - style: rowStyle ? (XEUtils.isFunction(rowStyle) ? rowStyle(params) : rowStyle) : null, - key: rowKey || rowOpts.useKey || rowOpts.drag || treeConfig ? rowid : $rowIndex, - ...trOn - }, tableColumn.map((column: any, $columnIndex: any) => { - return renderColumn(seq, rowid, fixedType, rowLevel, row, rowIndex, $rowIndex, _rowIndex, column, $columnIndex, tableColumn, tableData) - })) + columnOpts.drag + ? h(TransitionGroup, { + name: `vxe-header--col-list${isDragColMove ? '' : '-disabled'}`, + tag: 'tr', + class: trClass, + rowid: rowid, + style: rowStyle ? (XEUtils.isFunction(rowStyle) ? rowStyle(params) : rowStyle) : null, + key: rowKey || rowOpts.useKey || rowOpts.drag || treeConfig ? rowid : $rowIndex, + ...trOn + }, { + default: () => tdVNs + }) + : h('tr', { + class: trClass, + rowid: rowid, + style: rowStyle ? (XEUtils.isFunction(rowStyle) ? rowStyle(params) : rowStyle) : null, + key: rowKey || rowOpts.useKey || rowOpts.drag || treeConfig ? rowid : $rowIndex, + ...trOn + }, tdVNs) ) // 如果行被展开了 if (isExpandRow) { @@ -578,10 +593,8 @@ export default defineComponent({ const leftElem = leftBody ? leftBody.$el as HTMLDivElement : null const rightElem = rightBody ? rightBody.$el as HTMLDivElement : null const bodyElem = tableBody.$el as HTMLDivElement - const bodyYRef = elemStore['main-body-ySpace'] - const bodyYElem = bodyYRef ? bodyYRef.value : null - const bodyXRef = elemStore['main-body-xSpace'] - const bodyXElem = bodyXRef ? bodyXRef.value : null + const bodyYElem = getRefElem(elemStore['main-body-ySpace']) + const bodyXElem = getRefElem(elemStore['main-body-xSpace']) const bodyHeight = scrollYLoad && bodyYElem ? bodyYElem.clientHeight : bodyElem.clientHeight const bodyWidth = scrollXLoad && bodyXElem ? bodyXElem.clientWidth : bodyElem.clientWidth const remainSize = isPrevWheelTop === isTopWheel ? Math.max(0, wheelYSize - wheelYTotal) : 0 @@ -712,6 +725,7 @@ export default defineComponent({ const emptyOpts = computeEmptyOpts.value const keyboardOpts = computeKeyboardOpts.value const mouseOpts = computeMouseOpts.value + const columnOpts = computeColumnOpts.value // const isMergeLeftFixedExceeded = computeIsMergeLeftFixedExceeded.value // const isMergeRightFixedExceeded = computeIsMergeRightFixedExceeded.value // 如果是使用优化模式 @@ -787,8 +801,9 @@ export default defineComponent({ /** * 内容 */ - rowOpts.drag + rowOpts.drag || columnOpts.drag ? h(TransitionGroup, { + ref: refBodyTBody, name: `vxe-body--row-list${isDragRowMove ? '' : '-disabled'}`, tag: 'tbody' }, { diff --git a/packages/table/src/cell.ts b/packages/table/src/cell.ts index 4a6d97a3d2..9525b237e3 100644 --- a/packages/table/src/cell.ts +++ b/packages/table/src/cell.ts @@ -13,45 +13,46 @@ const { getI18n, getIcon, renderer, formats, renderEmptyElement } = VxeUI function renderTitlePrefixIcon (params: VxeTableDefines.CellRenderHeaderParams) { const { $table, column } = params const titlePrefix = column.titlePrefix || column.titleHelp - return titlePrefix - ? [ - h('i', { - class: ['vxe-cell-title-prefix-icon', titlePrefix.icon || getIcon().TABLE_TITLE_PREFIX], - onMouseenter (evnt: MouseEvent) { - $table.triggerHeaderTitleEvent(evnt, titlePrefix, params) - }, - onMouseleave (evnt: MouseEvent) { - $table.handleTargetLeaveEvent(evnt) - } - }) - ] - : [] + if (titlePrefix) { + return h('i', { + class: ['vxe-cell-title-prefix-icon', titlePrefix.icon || getIcon().TABLE_TITLE_PREFIX], + onMouseenter (evnt: MouseEvent) { + $table.triggerHeaderTitleEvent(evnt, titlePrefix, params) + }, + onMouseleave (evnt: MouseEvent) { + $table.handleTargetLeaveEvent(evnt) + } + }) + } + return renderEmptyElement($table) } function renderTitleSuffixIcon (params: VxeTableDefines.CellRenderHeaderParams) { const { $table, column } = params const titleSuffix = column.titleSuffix - return titleSuffix - ? [ - h('i', { - class: ['vxe-cell-title-suffix-icon', titleSuffix.icon || getIcon().TABLE_TITLE_SUFFIX], - onMouseenter (evnt: MouseEvent) { - $table.triggerHeaderTitleEvent(evnt, titleSuffix, params) - }, - onMouseleave (evnt: MouseEvent) { - $table.handleTargetLeaveEvent(evnt) - } - }) - ] - : [] + if (titleSuffix) { + h('i', { + class: ['vxe-cell-title-suffix-icon', titleSuffix.icon || getIcon().TABLE_TITLE_SUFFIX], + onMouseenter (evnt: MouseEvent) { + $table.triggerHeaderTitleEvent(evnt, titleSuffix, params) + }, + onMouseleave (evnt: MouseEvent) { + $table.handleTargetLeaveEvent(evnt) + } + }) + } + return renderEmptyElement($table) } function renderCellDragIcon (params: VxeTableDefines.CellRenderBodyParams) { const { $table } = params - const { computeDragOpts } = $table.getComputeMaps() - const dragOpts = computeDragOpts.value - const { rowIcon, rowDisabledMethod } = dragOpts - const isDisabled = rowDisabledMethod && rowDisabledMethod(params) + const tableProps = $table.props + const { dragConfig } = tableProps + const { computeRowDragOpts } = $table.getComputeMaps() + const rowDragOpts = computeRowDragOpts.value + const { icon, disabledMethod } = rowDragOpts + const rDisabledMethod = disabledMethod || (dragConfig ? dragConfig.rowDisabledMethod : null) + const isDisabled = rDisabledMethod && rDisabledMethod(params) return h('span', { key: 'dg', class: ['vxe-cell--drag-handle', { @@ -65,7 +66,7 @@ function renderCellDragIcon (params: VxeTableDefines.CellRenderBodyParams) { onMouseup: $table.handleCellDragMouseupEvent }, [ h('i', { - class: rowIcon || getIcon().TABLE_DRAG_ROW + class: icon || (dragConfig ? dragConfig.rowIcon : '') || getIcon().TABLE_DRAG_ROW }) ]) } @@ -74,13 +75,14 @@ function renderCellBaseVNs (params: VxeTableDefines.CellRenderBodyParams, conten const { $table, column, level } = params const { dragSort } = column const tableProps = $table.props - const { treeConfig } = tableProps - const { computeRowOpts, computeDragOpts } = $table.getComputeMaps() + const { treeConfig, dragConfig } = tableProps + const { computeRowOpts, computeRowDragOpts } = $table.getComputeMaps() const rowOpts = computeRowOpts.value - const dragOpts = computeDragOpts.value - const { showRowIcon, rowVisibleMethod } = dragOpts + const rowDragOpts = computeRowDragOpts.value + const { showIcon, visibleMethod } = rowDragOpts + const rVisibleMethod = visibleMethod || (dragConfig ? dragConfig.rowVisibleMethod : null) const vns: VxeComponentSlotType[] = XEUtils.isArray(content) ? content : [content] - if (dragSort && rowOpts.drag && (showRowIcon && (!rowVisibleMethod || rowVisibleMethod(params)))) { + if (dragSort && rowOpts.drag && ((showIcon || (dragConfig ? dragConfig.showRowIcon : false)) && (!rVisibleMethod || rVisibleMethod(params)))) { if (!treeConfig || !level) { vns.unshift( renderCellDragIcon(params) @@ -90,6 +92,46 @@ function renderCellBaseVNs (params: VxeTableDefines.CellRenderBodyParams, conten return vns } +function renderHeaderCellDragIcon (params: VxeTableDefines.CellRenderHeaderParams) { + const { $table, column } = params + const { computeColumnOpts, computeColumnDragOpts } = $table.getComputeMaps() + const columnOpts = computeColumnOpts.value + const columnDragOpts = computeColumnDragOpts.value + const { showIcon, icon, visibleMethod, disabledMethod } = columnDragOpts + const isDisabled = disabledMethod && disabledMethod(params) + if (columnOpts.drag && showIcon && (!visibleMethod || visibleMethod(params))) { + if (!(column.fixed || column.parentId)) { + return h('span', { + key: 'dg', + class: ['vxe-cell--drag-handle', { + 'is--disabled': isDisabled + }], + onMousedown (evnt) { + if (!isDisabled) { + $table.handleHeaderCellDragMousedownEvent(evnt, params) + } + }, + onMouseup: $table.handleHeaderCellDragMouseupEvent + }, [ + h('i', { + class: icon || getIcon().TABLE_DRAG_COLUMN + }) + ]) + } + } + return renderEmptyElement($table) +} + +function renderHeaderCellBaseVNs (params: VxeTableDefines.CellRenderHeaderParams, content: VNode | VNode[]) { + const vns = [ + renderTitlePrefixIcon(params), + renderHeaderCellDragIcon(params), + ...(XEUtils.isArray(content) ? content : [content]), + renderTitleSuffixIcon(params) + ] + return vns +} + function renderTitleContent (params: VxeTableDefines.CellRenderHeaderParams, content: VxeComponentSlotType | VxeComponentSlotType[]) { const { $table, column } = params const { props, reactData } = $table @@ -264,7 +306,7 @@ export const Cell = { return createColumn($xeTable, columnOpts, renConfs) }, /** - * 单元格 + * 列头标题 */ renderHeaderTitle (params: VxeTableDefines.CellRenderHeaderParams) { const { $table, column } = params @@ -286,7 +328,7 @@ export const Cell = { return renderTitleContent(params, formatText(column.getTitle(), 1)) }, renderDefaultHeader (params: VxeTableDefines.CellRenderHeaderParams) { - return renderTitlePrefixIcon(params).concat(Cell.renderHeaderTitle(params)).concat(renderTitleSuffixIcon(params)) + return renderHeaderCellBaseVNs(params, Cell.renderHeaderTitle(params)) }, renderDefaultCell (params: VxeTableDefines.CellRenderBodyParams) { const { $table, row, column } = params @@ -404,13 +446,13 @@ export const Cell = { }, /** - * 索引 + * 序号 */ renderSeqHeader (params: VxeTableDefines.CellRenderHeaderParams) { const { $table, column } = params const { slots } = column const headerSlot = slots ? slots.header : null - return renderTitleContent(params, headerSlot ? $table.callSlot(headerSlot, params) : formatText(column.getTitle(), 1)) + return renderHeaderCellBaseVNs(params, renderTitleContent(params, headerSlot ? $table.callSlot(headerSlot, params) : formatText(column.getTitle(), 1))) }, renderSeqCell (params: VxeTableDefines.CellRenderBodyParams) { const { $table, column } = params @@ -441,13 +483,15 @@ export const Cell = { const { slots } = column const headerSlot = slots ? slots.header : null const titleSlot = slots ? slots.title : null - return renderTitleContent(params, headerSlot - ? $table.callSlot(headerSlot, params) - : [ - h('span', { - class: 'vxe-radio--label' - }, titleSlot ? $table.callSlot(titleSlot, params) : formatText(column.getTitle(), 1)) - ]) + return renderHeaderCellBaseVNs(params, + renderTitleContent(params, headerSlot + ? $table.callSlot(headerSlot, params) + : [ + h('span', { + class: 'vxe-radio--label' + }, titleSlot ? $table.callSlot(titleSlot, params) : formatText(column.getTitle(), 1)) + ]) + ) }, renderRadioCell (params: VxeTableDefines.CellRenderBodyParams) { const { $table, column, isHidden } = params @@ -535,36 +579,38 @@ export const Cell = { } const checkboxParams = { ...params, checked: isAllCheckboxSelected, disabled: isAllCheckboxDisabled, indeterminate: isAllCheckboxIndeterminate } if (headerSlot) { - return renderTitleContent(checkboxParams, $table.callSlot(headerSlot, checkboxParams)) + return renderHeaderCellBaseVNs(params, renderTitleContent(checkboxParams, $table.callSlot(headerSlot, checkboxParams))) } if (checkboxOpts.checkStrictly ? !checkboxOpts.showHeader : checkboxOpts.showHeader === false) { - return renderTitleContent(checkboxParams, [ + return renderHeaderCellBaseVNs(params, renderTitleContent(checkboxParams, [ h('span', { class: 'vxe-checkbox--label' }, titleSlot ? $table.callSlot(titleSlot, checkboxParams) : headerTitle) - ]) + ])) } - return renderTitleContent(checkboxParams, [ - h('span', { - class: ['vxe-cell--checkbox', { - 'is--checked': isAllCheckboxSelected, - 'is--disabled': isAllCheckboxDisabled, - 'is--indeterminate': isAllCheckboxIndeterminate - }], - title: getI18n('vxe.table.allTitle'), - ...ons - }, [ + return renderHeaderCellBaseVNs(params, + renderTitleContent(checkboxParams, [ h('span', { - class: ['vxe-checkbox--icon', isAllCheckboxIndeterminate ? getIcon().TABLE_CHECKBOX_INDETERMINATE : (isAllCheckboxSelected ? getIcon().TABLE_CHECKBOX_CHECKED : getIcon().TABLE_CHECKBOX_UNCHECKED)] - }) - ].concat(titleSlot || headerTitle - ? [ - h('span', { - class: 'vxe-checkbox--label' - }, titleSlot ? $table.callSlot(titleSlot, checkboxParams) : headerTitle) - ] - : [])) - ]) + class: ['vxe-cell--checkbox', { + 'is--checked': isAllCheckboxSelected, + 'is--disabled': isAllCheckboxDisabled, + 'is--indeterminate': isAllCheckboxIndeterminate + }], + title: getI18n('vxe.table.allTitle'), + ...ons + }, [ + h('span', { + class: ['vxe-checkbox--icon', isAllCheckboxIndeterminate ? getIcon().TABLE_CHECKBOX_INDETERMINATE : (isAllCheckboxSelected ? getIcon().TABLE_CHECKBOX_CHECKED : getIcon().TABLE_CHECKBOX_UNCHECKED)] + }) + ].concat(titleSlot || headerTitle + ? [ + h('span', { + class: 'vxe-checkbox--label' + }, titleSlot ? $table.callSlot(titleSlot, checkboxParams) : headerTitle) + ] + : [])) + ]) + ) }, renderCheckboxCell (params: VxeTableDefines.CellRenderBodyParams) { const { $table, row, column, isHidden } = params @@ -786,23 +832,21 @@ export const Cell = { ]) }, renderTreeHTMLCell (params: VxeTableDefines.CellRenderBodyParams) { - return Cell.renderTreeIcon(params, Cell.renderHTMLCell(params) as VNode[]) + return Cell.renderTreeIcon(params, Cell.renderHTMLCell(params)) }, /** * 排序和筛选 */ renderSortAndFilterHeader (params: VxeTableDefines.CellRenderHeaderParams) { - return Cell.renderDefaultHeader(params) - .concat(Cell.renderSortIcon(params)) - .concat(Cell.renderFilterIcon(params)) + return renderHeaderCellBaseVNs(params, Cell.renderHeaderTitle(params).concat(Cell.renderSortIcon(params).concat(Cell.renderFilterIcon(params)))) }, /** * 排序 */ renderSortHeader (params: VxeTableDefines.CellRenderHeaderParams) { - return Cell.renderDefaultHeader(params).concat(Cell.renderSortIcon(params)) + return renderHeaderCellBaseVNs(params, Cell.renderHeaderTitle(params).concat(Cell.renderSortIcon(params))) }, renderSortIcon (params: VxeTableDefines.CellRenderHeaderParams | VxeTableDefines.CellRenderHeaderParams) { const { $table, column } = params @@ -845,7 +889,7 @@ export const Cell = { * 筛选 */ renderFilterHeader (params: VxeTableDefines.CellRenderHeaderParams) { - return Cell.renderDefaultHeader(params).concat(Cell.renderFilterIcon(params)) + return renderHeaderCellBaseVNs(params, Cell.renderHeaderTitle(params).concat(Cell.renderFilterIcon(params))) }, renderFilterIcon (params: VxeTableDefines.CellRenderHeaderParams) { const { $table, column, hasFilter } = params @@ -892,22 +936,26 @@ export const Cell = { isRequired = columnRules.some((rule) => rule.required) } } - return (isEnableConf(editConfig) - ? [ - isRequired && editOpts.showAsterisk - ? h('i', { - class: 'vxe-cell--required-icon' - }) - : null, - isEnableConf(editRender) && editOpts.showIcon - ? h('i', { - class: ['vxe-cell--edit-icon', editOpts.icon || getIcon().TABLE_EDIT] - }) - : null - ] - : []).concat(Cell.renderDefaultHeader(params)) - .concat(sortable ? Cell.renderSortIcon(params) : []) - .concat(filters ? Cell.renderFilterIcon(params) : []) + let editIconVNs: VNode[] = [] + if (isEnableConf(editConfig)) { + editIconVNs = [ + isRequired && editOpts.showAsterisk + ? h('i', { + class: 'vxe-cell--required-icon' + }) + : renderEmptyElement($table), + isEnableConf(editRender) && editOpts.showIcon + ? h('i', { + class: ['vxe-cell--edit-icon', editOpts.icon || getIcon().TABLE_EDIT] + }) + : renderEmptyElement($table) + ] + } + return renderHeaderCellBaseVNs(params, + editIconVNs.concat(Cell.renderHeaderTitle(params)) + .concat(sortable ? Cell.renderSortIcon(params) : []) + .concat(filters ? Cell.renderFilterIcon(params) : []) + ) }, // 行格编辑模式 renderRowEdit (params: VxeTableDefines.CellRenderBodyParams) { diff --git a/packages/table/src/emits.ts b/packages/table/src/emits.ts index 96dbdd0785..b809fd8a93 100644 --- a/packages/table/src/emits.ts +++ b/packages/table/src/emits.ts @@ -45,6 +45,9 @@ export default [ 'row-dragstart', 'row-dragover', 'row-dragend', + 'column-dragstart', + 'column-dragover', + 'column-dragend', 'edit-actived', // 废弃 diff --git a/packages/table/src/footer.ts b/packages/table/src/footer.ts index 0a3315a882..750db378e6 100644 --- a/packages/table/src/footer.ts +++ b/packages/table/src/footer.ts @@ -1,4 +1,4 @@ -import { createCommentVNode, defineComponent, h, ref, Ref, PropType, inject, nextTick, onMounted, onUnmounted } from 'vue' +import { createCommentVNode, defineComponent, TransitionGroup, h, ref, Ref, PropType, inject, nextTick, onMounted, onUnmounted } from 'vue' import XEUtils from 'xe-utils' import { VxeUI } from '../../ui' import { updateCellTitle, getPropClass, setScrollLeft } from '../../ui/src/dom' @@ -85,37 +85,173 @@ export default defineComponent({ } } - onMounted(() => { - nextTick(() => { - const { fixedType } = props - const { elemStore } = tableInternalData - const prefix = `${fixedType || 'main'}-footer-` - elemStore[`${prefix}wrapper`] = refElem - elemStore[`${prefix}table`] = refFooterTable - elemStore[`${prefix}colgroup`] = refFooterColgroup - elemStore[`${prefix}list`] = refFooterTFoot - elemStore[`${prefix}xSpace`] = refFooterXSpace - }) - }) - - onUnmounted(() => { + const renderRows = (tableColumn: VxeTableDefines.ColumnInfo[], footerTableData: any[], row: any, $rowIndex: number, _rowIndex: number) => { const { fixedType } = props - const { elemStore } = tableInternalData - const prefix = `${fixedType || 'main'}-footer-` - elemStore[`${prefix}wrapper`] = null - elemStore[`${prefix}table`] = null - elemStore[`${prefix}colgroup`] = null - elemStore[`${prefix}list`] = null - elemStore[`${prefix}xSpace`] = null - }) + const { footerCellClassName, footerCellStyle, footerAlign: allFooterAlign, footerSpanMethod, align: allAlign, columnKey, showFooterOverflow: allColumnFooterOverflow } = tableProps + const { scrollXLoad, overflowX, scrollbarWidth, currentColumn, mergeFooterList } = tableReactData + const tooltipOpts = computeTooltipOpts.value + const columnOpts = computeColumnOpts.value + + return tableColumn.map((column, $columnIndex) => { + const { type, showFooterOverflow, footerAlign, align, footerClassName, editRender, cellRender } = column + const renderOpts = editRender || cellRender + const compConf = renderOpts ? renderer.get(renderOpts.name) : null + const showAllTip = tooltipOpts.showAll + const isColGroup = column.children && column.children.length + const fixedHiddenColumn = fixedType ? column.fixed !== fixedType && !isColGroup : column.fixed && overflowX + const footOverflow = XEUtils.eqNull(showFooterOverflow) ? allColumnFooterOverflow : showFooterOverflow + const footAlign = footerAlign || (compConf ? compConf.tableFooterCellAlign : '') || allFooterAlign || align || (compConf ? compConf.tableCellAlign : '') || allAlign + let showEllipsis = footOverflow === 'ellipsis' + const showTitle = footOverflow === 'title' + const showTooltip = footOverflow === true || footOverflow === 'tooltip' + let hasEllipsis = showTitle || showTooltip || showEllipsis + const attrs: any = { colid: column.id } + const tfOns: any = {} + const columnIndex = $xeTable.getColumnIndex(column) + const _columnIndex = $xeTable.getVTColumnIndex(column) + const itemIndex = _columnIndex + const cellParams: VxeTableDefines.CellRenderFooterParams = { + $table: $xeTable, + $grid: $xeTable.xegrid, + row, + rowIndex: _rowIndex, + _rowIndex, + $rowIndex, + column, + columnIndex, + $columnIndex, + _columnIndex, + itemIndex, + items: row, + fixed: fixedType, + type: renderType, + data: footerTableData + } + // 纵向虚拟滚动不支持动态行高 + if (scrollXLoad && !hasEllipsis) { + showEllipsis = hasEllipsis = true + } + if (showTitle || showTooltip || showAllTip) { + tfOns.onMouseenter = (evnt: MouseEvent) => { + if (showTitle) { + updateCellTitle(evnt.currentTarget, column) + } else if (showTooltip || showAllTip) { + $xeTable.triggerFooterTooltipEvent(evnt, cellParams) + } + } + } + if (showTooltip || showAllTip) { + tfOns.onMouseleave = (evnt: MouseEvent) => { + if (showTooltip || showAllTip) { + $xeTable.handleTargetLeaveEvent(evnt) + } + } + } + tfOns.onClick = (evnt: MouseEvent) => { + $xeTable.dispatchEvent('footer-cell-click', Object.assign({ cell: evnt.currentTarget }, cellParams), evnt) + } + tfOns.onDblclick = (evnt: MouseEvent) => { + $xeTable.dispatchEvent('footer-cell-dblclick', Object.assign({ cell: evnt.currentTarget }, cellParams), evnt) + } + // 合并行或列 + if (mergeFooterList.length) { + const spanRest = mergeFooterMethod(mergeFooterList, _rowIndex, _columnIndex) + if (spanRest) { + const { rowspan, colspan } = spanRest + if (!rowspan || !colspan) { + return null + } + if (rowspan > 1) { + attrs.rowspan = rowspan + } + if (colspan > 1) { + attrs.colspan = colspan + } + } + } else if (footerSpanMethod) { + // 自定义合并方法 + const { rowspan = 1, colspan = 1 } = footerSpanMethod(cellParams) || {} + if (!rowspan || !colspan) { + return null + } + if (rowspan > 1) { + attrs.rowspan = rowspan + } + if (colspan > 1) { + attrs.colspan = colspan + } + } + return h('td', { + class: ['vxe-footer--column', column.id, { + [`col--${footAlign}`]: footAlign, + [`col--${type}`]: type, + 'col--last': $columnIndex === tableColumn.length - 1, + 'fixed--hidden': fixedHiddenColumn, + 'col--ellipsis': hasEllipsis, + 'col--current': currentColumn === column + }, getPropClass(footerClassName, cellParams), getPropClass(footerCellClassName, cellParams)], + ...attrs, + style: footerCellStyle ? (XEUtils.isFunction(footerCellStyle) ? footerCellStyle(cellParams) : footerCellStyle) : null, + ...tfOns, + key: columnKey || columnOpts.useKey || columnOpts.drag ? column.id : $columnIndex + }, [ + h('div', { + class: ['vxe-cell', { + 'c--title': showTitle, + 'c--tooltip': showTooltip, + 'c--ellipsis': showEllipsis + }] + }, column.renderFooter(cellParams)) + ]) + }).concat(scrollbarWidth + ? [ + h('td', { + key: `gr${$rowIndex}`, + class: 'vxe-footer--gutter col--gutter' + }) + ] + : []) + } + + const renderHeads = (footerTableData: any[]) => { + const { fixedType, tableColumn } = props + const { footerRowClassName, footerRowStyle } = tableProps + const { isDragColMove } = tableReactData + const columnOpts = computeColumnOpts.value + + return footerTableData.map((row, $rowIndex) => { + const _rowIndex = $rowIndex + const rowParams = { $table: $xeTable, row, _rowIndex, $rowIndex, fixed: fixedType, type: renderType } + + if (columnOpts.drag) { + return h(TransitionGroup, { + name: `vxe-header--col-list${isDragColMove ? '' : '-disabled'}`, + tag: 'tr', + class: [ + 'vxe-footer--row', + footerRowClassName ? XEUtils.isFunction(footerRowClassName) ? footerRowClassName(rowParams) : footerRowClassName : '' + ], + style: footerRowStyle ? (XEUtils.isFunction(footerRowStyle) ? footerRowStyle(rowParams) : footerRowStyle) : null + }, { + default: () => renderRows(tableColumn, footerTableData, row, $rowIndex, _rowIndex) + }) + } + return h('tr', { + class: [ + 'vxe-footer--row', + footerRowClassName ? XEUtils.isFunction(footerRowClassName) ? footerRowClassName(rowParams) : footerRowClassName : '' + ], + style: footerRowStyle ? (XEUtils.isFunction(footerRowStyle) ? footerRowStyle(rowParams) : footerRowStyle) : null + }, renderRows(tableColumn, footerTableData, row, $rowIndex, _rowIndex)) + }) + } const renderVN = () => { let { fixedType, fixedColumn, tableColumn, footerTableData } = props - const { footerRowClassName, footerCellClassName, footerRowStyle, footerCellStyle, footerAlign: allFooterAlign, footerSpanMethod, align: allAlign, columnKey, showFooterOverflow: allColumnFooterOverflow } = tableProps + const { footerSpanMethod, showFooterOverflow: allColumnFooterOverflow } = tableProps const { visibleColumn } = tableInternalData - const { scrollXLoad, overflowX, scrollbarWidth, currentColumn, mergeFooterList } = tableReactData - const tooltipOpts = computeTooltipOpts.value - const columnOpts = computeColumnOpts.value + const { scrollXLoad, scrollbarWidth, mergeFooterList } = tableReactData + // 如果是使用优化模式 if (fixedType) { // 如果存在展开行使用全量渲染 @@ -129,6 +265,7 @@ export default defineComponent({ tableColumn = visibleColumn } } + return h('div', { ref: refElem, class: ['vxe-table--footer-wrapper', fixedType ? `fixed-${fixedType}--wrapper` : 'body--wrapper'], @@ -171,135 +308,35 @@ export default defineComponent({ */ h('tfoot', { ref: refFooterTFoot - }, footerTableData.map((list, _rowIndex) => { - const $rowIndex = _rowIndex - const rowParams = { $table: $xeTable, row: list, _rowIndex, $rowIndex, fixed: fixedType, type: renderType } - return h('tr', { - class: ['vxe-footer--row', footerRowClassName ? XEUtils.isFunction(footerRowClassName) ? footerRowClassName(rowParams) : footerRowClassName : ''], - style: footerRowStyle ? (XEUtils.isFunction(footerRowStyle) ? footerRowStyle(rowParams) : footerRowStyle) : null - }, tableColumn.map((column, $columnIndex) => { - const { type, showFooterOverflow, footerAlign, align, footerClassName, editRender, cellRender } = column - const renderOpts = editRender || cellRender - const compConf = renderOpts ? renderer.get(renderOpts.name) : null - const showAllTip = tooltipOpts.showAll - const isColGroup = column.children && column.children.length - const fixedHiddenColumn = fixedType ? column.fixed !== fixedType && !isColGroup : column.fixed && overflowX - const footOverflow = XEUtils.eqNull(showFooterOverflow) ? allColumnFooterOverflow : showFooterOverflow - const footAlign = footerAlign || (compConf ? compConf.tableFooterCellAlign : '') || allFooterAlign || align || (compConf ? compConf.tableCellAlign : '') || allAlign - let showEllipsis = footOverflow === 'ellipsis' - const showTitle = footOverflow === 'title' - const showTooltip = footOverflow === true || footOverflow === 'tooltip' - let hasEllipsis = showTitle || showTooltip || showEllipsis - const attrs: any = { colid: column.id } - const tfOns: any = {} - const columnIndex = $xeTable.getColumnIndex(column) - const _columnIndex = $xeTable.getVTColumnIndex(column) - const itemIndex = _columnIndex - const cellParams: VxeTableDefines.CellRenderFooterParams = { - $table: $xeTable, - $grid: $xeTable.xegrid, - row: list, - rowIndex: _rowIndex, - _rowIndex, - $rowIndex, - column, - columnIndex, - $columnIndex, - _columnIndex, - itemIndex, - items: list, - fixed: fixedType, - type: renderType, - data: footerTableData - } - // 纵向虚拟滚动不支持动态行高 - if (scrollXLoad && !hasEllipsis) { - showEllipsis = hasEllipsis = true - } - if (showTitle || showTooltip || showAllTip) { - tfOns.onMouseenter = (evnt: MouseEvent) => { - if (showTitle) { - updateCellTitle(evnt.currentTarget, column) - } else if (showTooltip || showAllTip) { - $xeTable.triggerFooterTooltipEvent(evnt, cellParams) - } - } - } - if (showTooltip || showAllTip) { - tfOns.onMouseleave = (evnt: MouseEvent) => { - if (showTooltip || showAllTip) { - $xeTable.handleTargetLeaveEvent(evnt) - } - } - } - tfOns.onClick = (evnt: MouseEvent) => { - $xeTable.dispatchEvent('footer-cell-click', Object.assign({ cell: evnt.currentTarget }, cellParams), evnt) - } - tfOns.onDblclick = (evnt: MouseEvent) => { - $xeTable.dispatchEvent('footer-cell-dblclick', Object.assign({ cell: evnt.currentTarget }, cellParams), evnt) - } - // 合并行或列 - if (mergeFooterList.length) { - const spanRest = mergeFooterMethod(mergeFooterList, _rowIndex, _columnIndex) - if (spanRest) { - const { rowspan, colspan } = spanRest - if (!rowspan || !colspan) { - return null - } - if (rowspan > 1) { - attrs.rowspan = rowspan - } - if (colspan > 1) { - attrs.colspan = colspan - } - } - } else if (footerSpanMethod) { - // 自定义合并方法 - const { rowspan = 1, colspan = 1 } = footerSpanMethod(cellParams) || {} - if (!rowspan || !colspan) { - return null - } - if (rowspan > 1) { - attrs.rowspan = rowspan - } - if (colspan > 1) { - attrs.colspan = colspan - } - } - return h('td', { - class: ['vxe-footer--column', column.id, { - [`col--${footAlign}`]: footAlign, - [`col--${type}`]: type, - 'col--last': $columnIndex === tableColumn.length - 1, - 'fixed--hidden': fixedHiddenColumn, - 'col--ellipsis': hasEllipsis, - 'col--current': currentColumn === column - }, getPropClass(footerClassName, cellParams), getPropClass(footerCellClassName, cellParams)], - ...attrs, - style: footerCellStyle ? (XEUtils.isFunction(footerCellStyle) ? footerCellStyle(cellParams) : footerCellStyle) : null, - ...tfOns, - key: columnKey || columnOpts.useKey ? column.id : $columnIndex - }, [ - h('div', { - class: ['vxe-cell', { - 'c--title': showTitle, - 'c--tooltip': showTooltip, - 'c--ellipsis': showEllipsis - }] - }, column.renderFooter(cellParams)) - ]) - }).concat(scrollbarWidth - ? [ - h('td', { - class: 'vxe-footer--gutter col--gutter' - }) - ] - : [])) - })) + }, renderHeads(footerTableData)) ]) ]) } + onMounted(() => { + nextTick(() => { + const { fixedType } = props + const { elemStore } = tableInternalData + const prefix = `${fixedType || 'main'}-footer-` + elemStore[`${prefix}wrapper`] = refElem + elemStore[`${prefix}table`] = refFooterTable + elemStore[`${prefix}colgroup`] = refFooterColgroup + elemStore[`${prefix}list`] = refFooterTFoot + elemStore[`${prefix}xSpace`] = refFooterXSpace + }) + }) + + onUnmounted(() => { + const { fixedType } = props + const { elemStore } = tableInternalData + const prefix = `${fixedType || 'main'}-footer-` + elemStore[`${prefix}wrapper`] = null + elemStore[`${prefix}table`] = null + elemStore[`${prefix}colgroup`] = null + elemStore[`${prefix}list`] = null + elemStore[`${prefix}xSpace`] = null + }) + return renderVN } }) diff --git a/packages/table/src/header.ts b/packages/table/src/header.ts index 509f836a9b..0b1ed93d96 100644 --- a/packages/table/src/header.ts +++ b/packages/table/src/header.ts @@ -1,4 +1,4 @@ -import { createCommentVNode, defineComponent, h, ref, Ref, PropType, inject, nextTick, watch, onMounted, onUnmounted } from 'vue' +import { createCommentVNode, defineComponent, TransitionGroup, h, ref, Ref, PropType, inject, nextTick, watch, onMounted, onUnmounted } from 'vue' import XEUtils from 'xe-utils' import { VxeUI } from '../../ui' import { convertHeaderColumnToRows, getColReMinWidth } from './util' @@ -135,43 +135,136 @@ export default defineComponent({ } } - watch(() => props.tableColumn, uploadColumn) - - onMounted(() => { - nextTick(() => { - const { fixedType } = props - const { internalData } = $xeTable - const { elemStore } = internalData - const prefix = `${fixedType || 'main'}-header-` - elemStore[`${prefix}wrapper`] = refElem - elemStore[`${prefix}table`] = refHeaderTable - elemStore[`${prefix}colgroup`] = refHeaderColgroup - elemStore[`${prefix}list`] = refHeaderTHead - elemStore[`${prefix}xSpace`] = refHeaderXSpace - elemStore[`${prefix}repair`] = refHeaderBorderRepair - uploadColumn() - }) - }) + const renderRows = (cols: VxeTableDefines.ColumnInfo[], $rowIndex: number) => { + const { fixedType } = props + const { resizable: allResizable, border, columnKey, headerCellClassName, headerCellStyle, showHeaderOverflow: allColumnHeaderOverflow, headerAlign: allHeaderAlign, align: allAlign, mouseConfig } = tableProps + const { currentColumn, scrollXLoad, overflowX, scrollbarWidth } = tableReactData + const columnOpts = computeColumnOpts.value + return cols.map((column, $columnIndex) => { + const { type, showHeaderOverflow, headerAlign, align, headerClassName, editRender, cellRender } = column + const colid = column.id + const renderOpts = editRender || cellRender + const compConf = renderOpts ? renderer.get(renderOpts.name) : null + const isColGroup = column.children && column.children.length + const fixedHiddenColumn = fixedType ? (column.fixed !== fixedType && !isColGroup) : !!column.fixed && overflowX + const headOverflow = XEUtils.eqNull(showHeaderOverflow) ? allColumnHeaderOverflow : showHeaderOverflow + const headAlign = headerAlign || (compConf ? compConf.tableHeaderCellAlign : '') || allHeaderAlign || align || (compConf ? compConf.tableCellAlign : '') || allAlign + let showEllipsis = headOverflow === 'ellipsis' + const showTitle = headOverflow === 'title' + const showTooltip = headOverflow === true || headOverflow === 'tooltip' + let hasEllipsis = showTitle || showTooltip || showEllipsis + const hasFilter = column.filters && column.filters.some((item) => item.checked) + const columnIndex = $xeTable.getColumnIndex(column) + const _columnIndex = $xeTable.getVTColumnIndex(column) + const params: VxeTableDefines.CellRenderHeaderParams = { $table: $xeTable, $grid: $xeTable.xegrid, $rowIndex, column, columnIndex, $columnIndex, _columnIndex, fixed: fixedType, type: renderType, isHidden: fixedHiddenColumn, hasFilter } + const thOns: any = { + onClick: (evnt: MouseEvent) => $xeTable.triggerHeaderCellClickEvent(evnt, params), + onDblclick: (evnt: MouseEvent) => $xeTable.triggerHeaderCellDblclickEvent(evnt, params) + } + // 横向虚拟滚动不支持动态行高 + if (scrollXLoad && !hasEllipsis) { + showEllipsis = hasEllipsis = true + } + // 按下事件处理 + if (mouseConfig) { + thOns.onMousedown = (evnt: MouseEvent) => $xeTable.triggerHeaderCellMousedownEvent(evnt, params) + } + // 拖拽行事件 + if (columnOpts.drag && !column.parentId) { + thOns.onDragstart = $xeTable.handleHeaderCellDragDragstartEvent + thOns.onDragend = $xeTable.handleHeaderCellDragDragendEvent + thOns.onDragover = $xeTable.handleHeaderCellDragDragoverEvent + } + return h('th', { + class: ['vxe-header--column', colid, { + [`col--${headAlign}`]: headAlign, + [`col--${type}`]: type, + 'col--last': $columnIndex === cols.length - 1, + 'col--fixed': column.fixed, + 'col--group': isColGroup, + 'col--ellipsis': hasEllipsis, + 'fixed--hidden': fixedHiddenColumn, + 'is--sortable': column.sortable, + 'col--filter': !!column.filters, + 'is--filter-active': hasFilter, + 'col--current': currentColumn === column + }, + headerClassName ? (XEUtils.isFunction(headerClassName) ? headerClassName(params) : headerClassName) : '', + headerCellClassName ? (XEUtils.isFunction(headerCellClassName) ? headerCellClassName(params) : headerCellClassName) : '' + ], + colid, + colspan: column.colSpan > 1 ? column.colSpan : null, + rowspan: column.rowSpan > 1 ? column.rowSpan : null, + style: headerCellStyle ? (XEUtils.isFunction(headerCellStyle) ? headerCellStyle(params) : headerCellStyle) : null, + ...thOns, + key: columnKey || columnOpts.useKey || columnOpts.drag || isColGroup ? colid : $columnIndex + }, [ + h('div', { + class: ['vxe-cell', { + 'c--title': showTitle, + 'c--tooltip': showTooltip, + 'c--ellipsis': showEllipsis + }] + }, column.renderHeader(params)), + /** + * 列宽拖动 + */ + !fixedHiddenColumn && !isColGroup && (XEUtils.isBoolean(column.resizable) ? column.resizable : (columnOpts.resizable || allResizable)) + ? h('div', { + class: ['vxe-resizable', { + 'is--line': !border || border === 'none' + }], + onMousedown: (evnt: MouseEvent) => resizeMousedown(evnt, params) + }) + : null + ]) + }).concat(scrollbarWidth + ? [ + h('th', { + key: `gr${$rowIndex}`, + class: 'vxe-header--gutter col--gutter' + }) + ] + : []) + } - onUnmounted(() => { + const renderHeads = (headerGroups: VxeTableDefines.ColumnInfo[][]) => { const { fixedType } = props - const { internalData } = $xeTable - const { elemStore } = internalData - const prefix = `${fixedType || 'main'}-header-` - elemStore[`${prefix}wrapper`] = null - elemStore[`${prefix}table`] = null - elemStore[`${prefix}colgroup`] = null - elemStore[`${prefix}list`] = null - elemStore[`${prefix}xSpace`] = null - elemStore[`${prefix}repair`] = null - }) + const { headerRowClassName, headerRowStyle } = tableProps + const { isDragColMove } = tableReactData + const columnOpts = computeColumnOpts.value + + return headerGroups.map((cols, $rowIndex) => { + const params = { $table: $xeTable, $rowIndex, fixed: fixedType, type: renderType } + + if (columnOpts.drag) { + return h(TransitionGroup, { + name: `vxe-header--col-list${isDragColMove ? '' : '-disabled'}`, + tag: 'tr', + class: [ + 'vxe-header--row', + headerRowClassName ? (XEUtils.isFunction(headerRowClassName) ? headerRowClassName(params) : headerRowClassName) : '' + ], + style: headerRowStyle ? (XEUtils.isFunction(headerRowStyle) ? headerRowStyle(params) : headerRowStyle) : null + }, { + default: () => renderRows(cols, $rowIndex) + }) + } + return h('tr', { + class: [ + 'vxe-header--row', + headerRowClassName ? (XEUtils.isFunction(headerRowClassName) ? headerRowClassName(params) : headerRowClassName) : '' + ], + style: headerRowStyle ? (XEUtils.isFunction(headerRowStyle) ? headerRowStyle(params) : headerRowStyle) : null + }, renderRows(cols, $rowIndex)) + }) + } const renderVN = () => { const { fixedType, fixedColumn, tableColumn } = props - const { resizable: allResizable, border, columnKey, headerRowClassName, headerCellClassName, headerRowStyle, headerCellStyle, showHeaderOverflow: allColumnHeaderOverflow, headerAlign: allHeaderAlign, align: allAlign, mouseConfig } = tableProps - const { isGroup, currentColumn, scrollXLoad, overflowX, scrollbarWidth } = tableReactData + const { showHeaderOverflow: allColumnHeaderOverflow } = tableProps + const { isGroup, scrollXLoad, scrollbarWidth } = tableReactData const { visibleColumn } = tableInternalData - const columnOpts = computeColumnOpts.value let headerGroups: VxeTableDefines.ColumnInfo[][] = headerColumn.value let renderColumnList = tableColumn as VxeTableDefines.ColumnInfo[] if (isGroup) { @@ -226,90 +319,7 @@ export default defineComponent({ */ h('thead', { ref: refHeaderTHead - }, headerGroups.map((cols, $rowIndex) => { - return h('tr', { - class: ['vxe-header--row', headerRowClassName ? (XEUtils.isFunction(headerRowClassName) ? headerRowClassName({ $table: $xeTable, $rowIndex, fixed: fixedType, type: renderType }) : headerRowClassName) : ''], - style: headerRowStyle ? (XEUtils.isFunction(headerRowStyle) ? headerRowStyle({ $table: $xeTable, $rowIndex, fixed: fixedType, type: renderType }) : headerRowStyle) : null - }, cols.map((column, $columnIndex) => { - const { type, showHeaderOverflow, headerAlign, align, headerClassName, editRender, cellRender } = column - const colid = column.id - const renderOpts = editRender || cellRender - const compConf = renderOpts ? renderer.get(renderOpts.name) : null - const isColGroup = column.children && column.children.length - const fixedHiddenColumn = fixedType ? (column.fixed !== fixedType && !isColGroup) : !!column.fixed && overflowX - const headOverflow = XEUtils.eqNull(showHeaderOverflow) ? allColumnHeaderOverflow : showHeaderOverflow - const headAlign = headerAlign || (compConf ? compConf.tableHeaderCellAlign : '') || allHeaderAlign || align || (compConf ? compConf.tableCellAlign : '') || allAlign - let showEllipsis = headOverflow === 'ellipsis' - const showTitle = headOverflow === 'title' - const showTooltip = headOverflow === true || headOverflow === 'tooltip' - let hasEllipsis = showTitle || showTooltip || showEllipsis - const hasFilter = column.filters && column.filters.some((item) => item.checked) - const columnIndex = $xeTable.getColumnIndex(column) - const _columnIndex = $xeTable.getVTColumnIndex(column) - const params: VxeTableDefines.CellRenderHeaderParams = { $table: $xeTable, $grid: $xeTable.xegrid, $rowIndex, column, columnIndex, $columnIndex, _columnIndex, fixed: fixedType, type: renderType, isHidden: fixedHiddenColumn, hasFilter } - const thOns: any = { - onClick: (evnt: MouseEvent) => $xeTable.triggerHeaderCellClickEvent(evnt, params), - onDblclick: (evnt: MouseEvent) => $xeTable.triggerHeaderCellDblclickEvent(evnt, params) - } - // 横向虚拟滚动不支持动态行高 - if (scrollXLoad && !hasEllipsis) { - showEllipsis = hasEllipsis = true - } - // 按下事件处理 - if (mouseConfig) { - thOns.onMousedown = (evnt: MouseEvent) => $xeTable.triggerHeaderCellMousedownEvent(evnt, params) - } - return h('th', { - class: ['vxe-header--column', colid, { - [`col--${headAlign}`]: headAlign, - [`col--${type}`]: type, - 'col--last': $columnIndex === cols.length - 1, - 'col--fixed': column.fixed, - 'col--group': isColGroup, - 'col--ellipsis': hasEllipsis, - 'fixed--hidden': fixedHiddenColumn, - 'is--sortable': column.sortable, - 'col--filter': !!column.filters, - 'is--filter-active': hasFilter, - 'col--current': currentColumn === column - }, - headerClassName ? (XEUtils.isFunction(headerClassName) ? headerClassName(params) : headerClassName) : '', - headerCellClassName ? (XEUtils.isFunction(headerCellClassName) ? headerCellClassName(params) : headerCellClassName) : '' - ], - colid, - colspan: column.colSpan > 1 ? column.colSpan : null, - rowspan: column.rowSpan > 1 ? column.rowSpan : null, - style: headerCellStyle ? (XEUtils.isFunction(headerCellStyle) ? headerCellStyle(params) : headerCellStyle) : null, - ...thOns, - key: columnKey || columnOpts.useKey || isColGroup ? colid : $columnIndex - }, [ - h('div', { - class: ['vxe-cell', { - 'c--title': showTitle, - 'c--tooltip': showTooltip, - 'c--ellipsis': showEllipsis - }] - }, column.renderHeader(params)), - /** - * 列宽拖动 - */ - !fixedHiddenColumn && !isColGroup && (XEUtils.isBoolean(column.resizable) ? column.resizable : (columnOpts.resizable || allResizable)) - ? h('div', { - class: ['vxe-resizable', { - 'is--line': !border || border === 'none' - }], - onMousedown: (evnt: MouseEvent) => resizeMousedown(evnt, params) - }) - : null - ]) - }).concat(scrollbarWidth - ? [ - h('th', { - class: 'vxe-header--gutter col--gutter' - }) - ] - : [])) - })) + }, renderHeads(headerGroups)) ]), /** * 其他 @@ -321,6 +331,37 @@ export default defineComponent({ ]) } + watch(() => props.tableColumn, uploadColumn) + + onMounted(() => { + nextTick(() => { + const { fixedType } = props + const { internalData } = $xeTable + const { elemStore } = internalData + const prefix = `${fixedType || 'main'}-header-` + elemStore[`${prefix}wrapper`] = refElem + elemStore[`${prefix}table`] = refHeaderTable + elemStore[`${prefix}colgroup`] = refHeaderColgroup + elemStore[`${prefix}list`] = refHeaderTHead + elemStore[`${prefix}xSpace`] = refHeaderXSpace + elemStore[`${prefix}repair`] = refHeaderBorderRepair + uploadColumn() + }) + }) + + onUnmounted(() => { + const { fixedType } = props + const { internalData } = $xeTable + const { elemStore } = internalData + const prefix = `${fixedType || 'main'}-header-` + elemStore[`${prefix}wrapper`] = null + elemStore[`${prefix}table`] = null + elemStore[`${prefix}colgroup`] = null + elemStore[`${prefix}list`] = null + elemStore[`${prefix}xSpace`] = null + elemStore[`${prefix}repair`] = null + }) + return renderVN } }) diff --git a/packages/table/src/props.ts b/packages/table/src/props.ts index fe7275cdd0..904cde88f6 100644 --- a/packages/table/src/props.ts +++ b/packages/table/src/props.ts @@ -187,8 +187,12 @@ export default { cellConfig: Object as PropType, // 行配置信息 rowConfig: Object as PropType, - // 可拖拽配置项 + // 已废弃,被 rowDragConfig 替换 dragConfig: Object as PropType, + // 行拖拽排序配置项 + rowDragConfig: Object as PropType, + // 列拖拽排序配置项 + columnDragConfig: Object as PropType, // 列调整配置项 resizableConfig: Object as PropType, // 序号配置项 diff --git a/packages/table/src/table.ts b/packages/table/src/table.ts index d7a61a7822..28d76edfb9 100644 --- a/packages/table/src/table.ts +++ b/packages/table/src/table.ts @@ -9,7 +9,7 @@ import TableHeaderComponent from './header' import TableFooterComponent from './footer' import tableProps from './props' import tableEmits from './emits' -import { getRowUniqueId, clearTableAllStatus, getRowkey, getRowid, rowToVisible, colToVisible, getCellValue, setCellValue, handleFieldOrColumn, toTreePathSeq, restoreScrollLocation, XEBodyScrollElement, getRootColumn } from './util' +import { getRowUniqueId, clearTableAllStatus, getRowkey, getRowid, rowToVisible, colToVisible, getCellValue, setCellValue, handleFieldOrColumn, toTreePathSeq, restoreScrollLocation, XEBodyScrollElement, getRootColumn, getRefElem } from './util' import { getSlotVNs } from '../../ui/src/vn' import { warnLog, errLog } from '../../ui/src/log' import TableCustomPanelComponent from '../module/custom/panel' @@ -259,10 +259,14 @@ export default defineComponent({ isHeader: false, isFooter: false }, + scrollVMLoading: false, isDragRowMove: false, dragRow: null, + isDragColMove: false, + dragCol: null, dragTipText: '', + _isResize: false, _isLoading: false }) @@ -372,7 +376,9 @@ export default defineComponent({ const refCellResizeBar = ref() as Ref const refEmptyPlaceholder = ref() as Ref - const refRowDragTipElem = ref() + const refDragTipElem = ref() + const refDragRowLineElem = ref() + const refDragColLineElem = ref() const refScrollXVirtualElem = ref() const refScrollYVirtualElem = ref() @@ -446,8 +452,12 @@ export default defineComponent({ return Object.assign({}, getConfig().table.rowConfig, props.rowConfig) as VxeTablePropTypes.RowOpts }) - const computeDragOpts = computed(() => { - return Object.assign({}, getConfig().table.dragConfig, props.dragConfig) as VxeTablePropTypes.DragConfig + const computeRowDragOpts = computed(() => { + return Object.assign({}, getConfig().table.rowDragConfig, props.rowDragConfig) + }) + + const computeColumnDragOpts = computed(() => { + return Object.assign({}, getConfig().table.columnDragConfig, props.columnDragConfig) }) const computeResizeOpts = computed(() => { @@ -702,7 +712,8 @@ export default defineComponent({ computeColumnOpts, computeCellOpts, computeRowOpts, - computeDragOpts, + computeRowDragOpts, + computeColumnDragOpts, computeResizeOpts, computeResizableOpts, computeSeqOpts, @@ -1662,8 +1673,7 @@ export default defineComponent({ const cellOffsetWidth = computeCellOffsetWidth.value const mouseOpts = computeMouseOpts.value const keyboardOpts = computeKeyboardOpts.value - const bodyWrapperRef = elemStore['main-body-wrapper'] - const bodyWrapperElem = bodyWrapperRef ? bodyWrapperRef.value : null + const bodyWrapperElem = getRefElem(elemStore['main-body-wrapper']) if (emptyPlaceholderElem) { emptyPlaceholderElem.style.top = `${headerHeight}px` emptyPlaceholderElem.style.height = bodyWrapperElem ? `${bodyWrapperElem.offsetHeight - scrollbarHeight}px` : '' @@ -1711,10 +1721,8 @@ export default defineComponent({ fixedWrapperElem = isFixedLeft ? refLeftContainer.value : refRightContainer.value } layoutList.forEach(layout => { - const wrapperRef = elemStore[`${name}-${layout}-wrapper`] - const wrapperElem = wrapperRef ? wrapperRef.value : null - const tableRef = elemStore[`${name}-${layout}-table`] - const tableElem = tableRef ? tableRef.value : null + const wrapperElem = getRefElem(elemStore[`${name}-${layout}-wrapper`]) + const tableElem = getRefElem(elemStore[`${name}-${layout}-table`]) if (layout === 'header') { // 表头体样式处理 // 横向滚动渲染 @@ -1738,14 +1746,12 @@ export default defineComponent({ tableElem.style.width = tWidth ? `${tWidth + scrollbarWidth}px` : '' } - const repairRef = elemStore[`${name}-${layout}-repair`] - const repairElem = repairRef ? repairRef.value : null + const repairElem = getRefElem(elemStore[`${name}-${layout}-repair`]) if (repairElem) { repairElem.style.width = `${tableWidth}px` } - const listRef = elemStore[`${name}-${layout}-list`] - const listElem = listRef ? listRef.value : null + const listElem = getRefElem(elemStore[`${name}-${layout}-list`]) if (isGroup && listElem) { XEUtils.arrayEach(listElem.querySelectorAll('.col--group'), (thElem: any) => { const colNode = tableMethods.getColumnNode(thElem) @@ -1772,8 +1778,7 @@ export default defineComponent({ }) } } else if (layout === 'body') { - const emptyBlockRef = elemStore[`${name}-${layout}-emptyBlock`] - const emptyBlockElem = emptyBlockRef ? emptyBlockRef.value : null + const emptyBlockElem = getRefElem(elemStore[`${name}-${layout}-emptyBlock`]) if (isNodeElement(wrapperElem)) { let bodyMaxHeight = 0 const bodyMinHeight = customMinHeight - headerHeight - footerHeight @@ -1867,8 +1872,7 @@ export default defineComponent({ tableElem.style.width = tWidth ? `${tWidth + scrollbarWidth}px` : '' } } - const colgroupRef = elemStore[`${name}-${layout}-colgroup`] - const colgroupElem = colgroupRef ? colgroupRef.value : null + const colgroupElem = getRefElem(elemStore[`${name}-${layout}-colgroup`]) if (colgroupElem) { XEUtils.arrayEach(colgroupElem.children, (colElem: any) => { const colid = colElem.getAttribute('name') @@ -1892,8 +1896,7 @@ export default defineComponent({ const showTitle = cellOverflow === 'title' const showTooltip = cellOverflow === true || cellOverflow === 'tooltip' let hasEllipsis = showTitle || showTooltip || showEllipsis - const listRef = elemStore[`${name}-${layout}-list`] - const listElem = listRef ? listRef.value : null + const listElem = getRefElem(elemStore[`${name}-${layout}-list`]) // 纵向虚拟滚动不支持动态行高 if (scrollYLoad && !hasEllipsis) { hasEllipsis = true @@ -2504,6 +2507,7 @@ export default defineComponent({ editStore.removeMaps = {} const sYLoad = updateScrollYStatus(fullData) reactData.scrollYLoad = sYLoad + reactData.isDragRowMove = false // 全量数据 internalData.tableFullData = fullData internalData.tableFullTreeData = treeData @@ -2762,6 +2766,7 @@ export default defineComponent({ const tableFullColumn = getColumnList(collectColumn) internalData.tableFullColumn = tableFullColumn reactData._isLoading = true + reactData.isDragColMove = false initColumnSort() return Promise.resolve( restoreCustomStorage() @@ -4988,8 +4993,8 @@ export default defineComponent({ updateCellAreas () { const { mouseConfig } = props const mouseOpts = computeMouseOpts.value - if (mouseConfig && mouseOpts.area && $xeTable.handleUpdateCellAreas) { - return $xeTable.handleUpdateCellAreas() + if (mouseConfig && mouseOpts.area && $xeTable.handleRecalculateCellAreas) { + return $xeTable.handleRecalculateCellAreas() } return nextTick() }, @@ -5182,7 +5187,7 @@ export default defineComponent({ !getEventTargetNode(evnt, el).flag ) { setTimeout(() => { - $xeTable.clearEdit(evnt).then(() => { + $xeTable.handleClearEdit(evnt).then(() => { // 如果存在校验,点击了表格之外则清除 if (!internalData.isActivated && editRules && validOpts.autoClear) { reactData.validErrorMaps = {} @@ -5262,8 +5267,8 @@ export default defineComponent({ if (isEsc) { tablePrivateMethods.preventEvent(evnt, 'event.keydown', null, () => { dispatchEvent('keydown-start', {}, evnt) - if (keyboardConfig && mouseConfig && mouseOpts.area && $xeTable.handleKeyboardEvent) { - $xeTable.handleKeyboardEvent(evnt) + if (keyboardConfig && mouseConfig && mouseOpts.area && $xeTable.handleKeyboardCellAreaEvent) { + $xeTable.handleKeyboardCellAreaEvent(evnt) } else if (actived.row || filterStore.visible || ctxMenuStore.visible) { evnt.stopPropagation() // 如果按下了 Esc 键,关闭快捷菜单、筛选 @@ -5275,7 +5280,7 @@ export default defineComponent({ // 如果是激活编辑状态,则取消编辑 if (actived.row) { const params = actived.args - $xeTable.clearEdit(evnt) + $xeTable.handleClearEdit(evnt) // 如果配置了选中功能,则为选中状态 if (mouseOpts.selected) { nextTick(() => $xeTable.handleSelected(params, evnt)) @@ -5337,8 +5342,8 @@ export default defineComponent({ } else { $xeTable.moveCtxMenu(evnt, ctxMenuStore, 'selected', isRightArrow, true, menuList) } - } else if (keyboardConfig && mouseConfig && mouseOpts.area && $xeTable.handleKeyboardEvent) { - $xeTable.handleKeyboardEvent(evnt) + } else if (keyboardConfig && mouseConfig && mouseOpts.area && $xeTable.handleKeyboardCellAreaEvent) { + $xeTable.handleKeyboardCellAreaEvent(evnt) } else if (isEsc) { // 如果按下了 Esc 键,关闭快捷菜单、筛选 if ($xeTable.closeMenu) { @@ -5349,7 +5354,7 @@ export default defineComponent({ // 如果是激活编辑状态,则取消编辑 if (actived.row) { const params = actived.args - $xeTable.clearEdit(evnt) + $xeTable.handleClearEdit(evnt) // 如果配置了选中功能,则为选中状态 if (mouseOpts.selected) { nextTick(() => $xeTable.handleSelected(params, evnt)) @@ -5385,7 +5390,7 @@ export default defineComponent({ // 如果是激活编辑状态,则取消编辑 if (actived.row) { const params = actived.args - $xeTable.clearEdit(evnt) + $xeTable.handleClearEdit(evnt) // 如果配置了选中功能,则为选中状态 if (mouseOpts.selected) { nextTick(() => $xeTable.handleSelected(params, evnt)) @@ -5599,8 +5604,8 @@ export default defineComponent({ if (!el || !el.clientWidth) { return nextTick() } - tableMethods.updateCellAreas() tableMethods.recalculate(true) + tableMethods.updateCellAreas() } const handleTargetEnterEvent = (isClear: boolean) => { @@ -5637,65 +5642,112 @@ export default defineComponent({ } } - const clearRowDropTarget = () => { + const updateRowDropTipContent = (tdEl: HTMLElement) => { + const { dragConfig } = props + const { dragRow } = reactData + const rowDragOpts = computeRowDragOpts.value + const { tooltipMethod } = rowDragOpts + const rTooltipMethod = tooltipMethod || (dragConfig ? dragConfig.rowTooltipMethod : null) + let tipContent = '' + if (rTooltipMethod) { + tipContent = `${rTooltipMethod({ + row: dragRow + }) || ''}` + } else { + tipContent = getI18n('vxe.table.dragTip', [tdEl.textContent || '']) + } + reactData.dragTipText = tipContent + } + + const updateColDropOrigin = (column: VxeTableDefines.ColumnInfo) => { const el = refElem.value if (el) { - const clss = 'row--drag-active-target' - XEUtils.arrayEach(el.querySelectorAll(`.${clss}`), (elem) => { - removeClass(elem, clss) + const clss = 'col--drag-origin' + XEUtils.arrayEach(el.querySelectorAll(`[colid="${column.id}"]`), (elem) => { + addClass(elem, clss) }) } } - const updateRowDropTarget = (row: any, dragPos: string) => { + const clearColDropOrigin = () => { const el = refElem.value if (el) { - const clss = 'row--drag-active-target' - const rowid = getRowid($xeTable, row) - XEUtils.arrayEach(el.querySelectorAll(`[rowid="${rowid}"]`), (elem) => { - addClass(elem, clss) - elem.setAttribute('drag-pos', dragPos) + const clss = 'col--drag-origin' + XEUtils.arrayEach(el.querySelectorAll(`.${clss}`), (elem) => { + (elem as HTMLTableCellElement).draggable = false + removeClass(elem, clss) }) } } - const showRowDropTip = (evnt: DragEvent | MouseEvent) => { - const rdTipEl = refRowDragTipElem.value - if (!rdTipEl) { - return + const updateColDropTipContent = (tdEl: HTMLElement) => { + const { dragCol } = reactData + const columnDragOpts = computeColumnDragOpts.value + const { tooltipMethod } = columnDragOpts + let tipContent = '' + if (tooltipMethod) { + tipContent = `${tooltipMethod({ + column: dragCol + }) || ''}` + } else { + tipContent = getI18n('vxe.table.dragTip', [tdEl.textContent || '']) } + reactData.dragTipText = tipContent + } + + const showDropTip = (evnt: DragEvent | MouseEvent, trEl: HTMLElement | null, thEl: HTMLElement | null, dragPos: string) => { const el = refElem.value if (!el) { return } + const { scrollbarWidth, scrollbarHeight } = reactData + const wrapperRect = el.getBoundingClientRect() + if (trEl) { + const rdLineEl = refDragRowLineElem.value + if (rdLineEl) { + const trRect = trEl.getBoundingClientRect() + let top = Math.max(1, trRect.y - wrapperRect.y) + if (dragPos === 'bottom') { + top = Math.min(wrapperRect.height - 1, trRect.y - wrapperRect.y + trRect.height) + } + rdLineEl.style.top = `${top}px` + rdLineEl.style.width = `${wrapperRect.width - scrollbarWidth}px` + rdLineEl.style.display = 'block' + } + } else if (thEl) { + const cdLineEl = refDragColLineElem.value + if (cdLineEl) { + const thRect = thEl.getBoundingClientRect() + let left = Math.max(1, thRect.x - wrapperRect.x) + if (dragPos === 'right') { + left = Math.min(wrapperRect.width - 2, thRect.x - wrapperRect.x + thRect.width) + } + cdLineEl.style.left = `${left}px` + cdLineEl.style.height = `${wrapperRect.height - scrollbarHeight}px` + cdLineEl.style.display = 'block' + } + } + const rdTipEl = refDragTipElem.value if (rdTipEl) { - const wrapperRect = el.getBoundingClientRect() rdTipEl.style.display = 'block' rdTipEl.style.top = `${Math.min(el.clientHeight - el.scrollTop - rdTipEl.clientHeight, evnt.clientY - wrapperRect.y)}px` rdTipEl.style.left = `${Math.min(el.clientWidth - el.scrollLeft - rdTipEl.clientWidth - 16, evnt.clientX - wrapperRect.x)}px` } } - const hideRowDropTip = () => { - const rdTipEl = refRowDragTipElem.value + const hideDropTip = () => { + const rdTipEl = refDragTipElem.value + const rdLineEl = refDragRowLineElem.value + const cdLineEl = refDragColLineElem.value if (rdTipEl) { rdTipEl.style.display = '' } - } - - const updateRowDropTipContent = (tdEl: HTMLElement) => { - const { dragRow } = reactData - const dragOpts = computeDragOpts.value - const { rowTooltipMethod } = dragOpts - let tipContent = '' - if (rowTooltipMethod) { - tipContent = `${rowTooltipMethod({ - row: dragRow - }) || ''}` - } else { - tipContent = getI18n('vxe.table.dragTip', [tdEl.textContent || '']) + if (rdLineEl) { + rdLineEl.style.display = '' + } + if (cdLineEl) { + cdLineEl.style.display = '' } - reactData.dragTipText = tipContent } /** @@ -6751,6 +6803,9 @@ export default defineComponent({ dispatchEvent('sort-change', params, evnt) } }, + /** + * 行拖拽 + */ handleRowDragDragstartEvent (evnt) { const img = new Image() if (evnt.dataTransfer) { @@ -6758,28 +6813,31 @@ export default defineComponent({ } }, handleRowDragDragendEvent (evnt) { - const { treeConfig } = props - const dragOpts = computeDragOpts.value - const { dragEndMethod } = dragOpts + const { treeConfig, dragConfig } = props + const rowDragOpts = computeRowDragOpts.value + const { dragEndMethod } = rowDragOpts const treeOpts = computeTreeOpts.value const { transform } = treeOpts const { dragRow } = reactData const { afterFullData, afterTreeFullData, tableFullData, tableFullTreeData, prevDragRow, prevDragPos } = internalData + const dEndMethod = dragEndMethod || (dragConfig ? dragConfig.dragEndMethod : null) + const dragOffsetIndex = prevDragPos === 'bottom' ? 1 : 0 if (prevDragRow && dragRow) { // 判断是否有拖动 if (prevDragRow !== dragRow) { Promise.resolve( - dragEndMethod - ? dragEndMethod({ + dEndMethod + ? dEndMethod({ oldRow: dragRow, - newRow: prevDragRow + newRow: prevDragRow, + dragPos: prevDragPos as any, + offsetIndex: dragOffsetIndex }) : true ).then((status) => { if (!status) { return } - const dragOffsetIndex = prevDragPos === 'bottom' ? 1 : 0 let oafIndex = -1 let nafIndex = -1 @@ -6790,7 +6848,7 @@ export default defineComponent({ afterTreeFullData.splice(oafIndex, 1) tableFullTreeData.splice(otfIndex, 1) - // 插新位置 + // 插入新位置 const pafIndex = $xeTable.findRowIndexOf(afterTreeFullData, prevDragRow) const ptfIndex = $xeTable.findRowIndexOf(tableFullTreeData, prevDragRow) nafIndex = pafIndex + dragOffsetIndex @@ -6803,7 +6861,7 @@ export default defineComponent({ const otfIndex = $xeTable.findRowIndexOf(tableFullData, dragRow) afterFullData.splice(oafIndex, 1) tableFullData.splice(otfIndex, 1) - // 插新位置 + // 插入新位置 const pafIndex = $xeTable.findRowIndexOf(afterFullData, prevDragRow) const ptfIndex = $xeTable.findRowIndexOf(tableFullData, prevDragRow) nafIndex = pafIndex + dragOffsetIndex @@ -6814,24 +6872,25 @@ export default defineComponent({ reactData.isDragRowMove = true $xeTable.cacheRowMap() - $xeTable.updateScrollYStatus() + updateScrollYStatus() $xeTable.handleTableData(treeConfig && transform) if (!(treeConfig && transform)) { $xeTable.updateAfterDataIndex() } - $xeTable.updateFooter() $xeTable.checkSelectionStatus() if (reactData.scrollYLoad) { $xeTable.updateScrollYSpace() } nextTick().then(() => { $xeTable.updateCellAreas() - return $xeTable.recalculate() + $xeTable.recalculate() }) dispatchEvent('row-dragend', { oldRow: dragRow, newRow: prevDragRow, + dragPos: prevDragPos as any, + offsetIndex: dragOffsetIndex, _index: { newIndex: nafIndex, oldIndex: oafIndex @@ -6841,65 +6900,217 @@ export default defineComponent({ }) } } - hideRowDropTip() + hideDropTip() clearRowDropOrigin() - clearRowDropTarget() reactData.dragRow = null + reactData.dragCol = null setTimeout(() => { reactData.isDragRowMove = false }, 500) }, handleRowDragDragoverEvent (evnt) { + const { dragRow } = reactData + if (!dragRow) { + evnt.preventDefault() + return + } const trEl = evnt.currentTarget as HTMLElement const rowid = trEl.getAttribute('rowid') const row = $xeTable.getRowById(rowid) - clearRowDropTarget() if (row) { evnt.preventDefault() evnt.preventDefault() const { dragRow } = reactData const offsetY = evnt.clientY - trEl.getBoundingClientRect().y const dragPos = offsetY < trEl.clientHeight / 2 ? 'top' : 'bottom' - updateRowDropTarget(row, dragPos) internalData.prevDragRow = row internalData.prevDragPos = dragPos + showDropTip(evnt, trEl, null, dragPos) dispatchEvent('row-dragover', { oldRow: dragRow, targetRow: row, dragPos }, evnt) } - showRowDropTip(evnt) }, handleCellDragMousedownEvent (evnt, params) { evnt.stopPropagation() - const dragOpts = computeDragOpts.value - const { dragStartMethod } = dragOpts + const { dragConfig } = props + const rowDragOpts = computeRowDragOpts.value + const { dragStartMethod } = rowDragOpts const { row } = params const dragEl = evnt.currentTarget as HTMLElement - const tdEl = dragEl.parentNode?.parentNode as HTMLElement - const trEl = tdEl.parentNode as HTMLElement + const tdEl = dragEl.parentElement?.parentElement as HTMLElement + const trEl = tdEl.parentElement as HTMLElement + const dStartMethod = dragStartMethod || (dragConfig ? dragConfig.dragStartMethod : null) reactData.isDragRowMove = false clearRowDropOrigin() - if (dragStartMethod && !dragStartMethod(params)) { + if (dStartMethod && !dStartMethod(params)) { trEl.draggable = false reactData.dragRow = null - hideRowDropTip() + reactData.dragCol = null + hideDropTip() return } reactData.dragRow = row + reactData.dragCol = null trEl.draggable = true updateRowDropOrigin(row) - showRowDropTip(evnt) updateRowDropTipContent(tdEl) dispatchEvent('row-dragstart', params, evnt) }, handleCellDragMouseupEvent () { clearRowDropOrigin() - hideRowDropTip() + hideDropTip() reactData.dragRow = null + reactData.dragCol = null reactData.isDragRowMove = false }, + /** + * 列拖拽 + */ + handleHeaderCellDragDragstartEvent (evnt) { + const img = new Image() + if (evnt.dataTransfer) { + evnt.dataTransfer.setDragImage(img, 0, 0) + } + }, + handleHeaderCellDragDragendEvent (evnt) { + const { mouseConfig } = props + const columnDragOpts = computeColumnDragOpts.value + const { dragEndMethod } = columnDragOpts + const { dragCol } = reactData + const { collectColumn, prevDragCol, prevDragPos } = internalData + const dragOffsetIndex = prevDragPos === 'right' ? 1 : 0 + if (prevDragCol && dragCol) { + // 判断是否有拖动 + if (prevDragCol !== dragCol) { + Promise.resolve( + dragEndMethod + ? dragEndMethod({ + oldColumn: dragCol, + newColumn: prevDragCol, + dragPos: prevDragPos as any, + offsetIndex: dragOffsetIndex + }) + : true + ).then((status) => { + if (!status) { + return + } + + XEUtils.eachTree(collectColumn, (column, index, items, path, parent) => { + if (!parent) { + const sortIndex = index + 1 + column.renderSortNumber = sortIndex + } + }) + + const oafIndex = XEUtils.findIndexOf(collectColumn, item => item.id === dragCol.id) + const nafIndex = XEUtils.findIndexOf(collectColumn, item => item.id === prevDragCol.id) + dragOffsetIndex + + const newTargetCol = collectColumn[nafIndex] + if (newTargetCol) { + // 插入最后位置 + dragCol.renderSortNumber = newTargetCol.renderSortNumber + newTargetCol.renderSortNumber = dragCol.renderSortNumber + 0.5 + } else { + // 插入新位置 + dragCol.renderSortNumber = collectColumn.length + 1.5 + } + + reactData.isDragColMove = true + if (mouseConfig) { + if ($xeTable.clearSelected) { + $xeTable.clearSelected() + } + if ($xeTable.clearCellAreas) { + $xeTable.clearCellAreas() + $xeTable.clearCopyCellArea() + } + } + tablePrivateMethods.analyColumnWidth() + nextTick().then(() => { + $xeTable.updateCellAreas() + tableMethods.refreshColumn(true) + }) + + dispatchEvent('column-dragend', { + oldColumn: dragCol, + newColumn: prevDragCol, + dragPos: prevDragPos, + offsetIndex: dragOffsetIndex, + _index: { + newIndex: nafIndex, + oldIndex: oafIndex + } + }, evnt) + }).catch(() => { + }) + } + } + hideDropTip() + clearColDropOrigin() + reactData.dragRow = null + reactData.dragCol = null + setTimeout(() => { + reactData.isDragColMove = false + }, 500) + }, + handleHeaderCellDragDragoverEvent (evnt) { + const { dragCol } = reactData + if (!dragCol) { + evnt.preventDefault() + return + } + const thEl = evnt.currentTarget as HTMLElement + const colid = thEl.getAttribute('colid') + const column = $xeTable.getColumnById(colid) + if (column) { + evnt.preventDefault() + const { dragCol } = reactData + const offsetX = evnt.clientX - thEl.getBoundingClientRect().x + const dragPos = offsetX < thEl.clientWidth / 2 ? 'left' : 'right' + internalData.prevDragCol = column + internalData.prevDragPos = dragPos + showDropTip(evnt, null, thEl, dragPos) + dispatchEvent('column-dragover', { + oldColumn: dragCol, + targetColumn: column, + dragPos + }, evnt) + } + }, + handleHeaderCellDragMousedownEvent (evnt, params) { + evnt.stopPropagation() + const columnDragOpts = computeColumnDragOpts.value + const { dragStartMethod } = columnDragOpts + const { column } = params + const dragEl = evnt.currentTarget as HTMLElement + const thEl = dragEl.parentElement?.parentElement as HTMLElement + reactData.isDragColMove = false + clearColDropOrigin() + if (dragStartMethod && !dragStartMethod(params)) { + thEl.draggable = false + reactData.dragRow = null + reactData.dragCol = null + hideDropTip() + return + } + reactData.dragCol = column + reactData.dragRow = null + thEl.draggable = true + updateColDropOrigin(column) + updateColDropTipContent(thEl) + dispatchEvent('column-dragstart', params, evnt) + }, + handleHeaderCellDragMouseupEvent () { + clearColDropOrigin() + hideDropTip() + reactData.dragRow = null + reactData.dragCol = null + reactData.isDragColMove = false + }, /** * 横向 X 可视渲染事件处理 */ @@ -7066,8 +7277,7 @@ export default defineComponent({ containerList.forEach(name => { const layoutList = ['header', 'body', 'footer'] layoutList.forEach(layout => { - const xSpaceRef = elemStore[`${name}-${layout}-xSpace`] - const xSpaceElem = xSpaceRef ? xSpaceRef.value : null + const xSpaceElem = getRefElem(elemStore[`${name}-${layout}-xSpace`]) if (xSpaceElem) { xSpaceElem.style.width = scrollXLoad ? `${tableWidth + (layout === 'header' ? scrollbarWidth : 0)}px` : '' } @@ -7118,14 +7328,12 @@ export default defineComponent({ } containerList.forEach(name => { const layoutList = ['header', 'body', 'footer'] - const tableRef = elemStore[`${name}-body-table`] - const tableElem = tableRef ? tableRef.value : null + const tableElem = getRefElem(elemStore[`${name}-body-table`]) if (tableElem) { tableElem.style.marginTop = marginTop } layoutList.forEach(layout => { - const ySpaceRef = elemStore[`${name}-${layout}-ySpace`] - const ySpaceElem = ySpaceRef ? ySpaceRef.value : null + const ySpaceElem = getRefElem(elemStore[`${name}-${layout}-ySpace`]) if (ySpaceElem) { ySpaceElem.style.height = ySpaceHeight } @@ -7305,6 +7513,50 @@ export default defineComponent({ return getFuncText(props.emptyText) || getI18n('vxe.table.emptyText') } + const renderDragTipContents = () => { + const { dragConfig } = props + const { dragRow, dragCol, dragTipText } = reactData + const columnDragOpts = computeColumnDragOpts.value + const rowDragOpts = computeRowDragOpts.value + const rowDragSlots = rowDragOpts.slots || {} + const rTipSlot = rowDragSlots.tip || (dragConfig && dragConfig.slots ? dragConfig.slots.rowTip : null) + const columnDragSlots = columnDragOpts.slots || {} + const cTipSlot = columnDragSlots.tip + + if (dragRow && rTipSlot) { + return callSlot(rTipSlot, { row: dragRow }) + } + if (dragCol && cTipSlot) { + return callSlot(cTipSlot, { column: dragCol }) + } + return [h('span', dragTipText)] + } + + const renderDragTip = () => { + const rowOpts = computeRowOpts.value + const columnOpts = computeColumnOpts.value + + if (rowOpts.drag || columnOpts.drag) { + return h('div', { + class: 'vxe-table--drag-wrapper' + }, [ + h('div', { + ref: refDragRowLineElem, + class: 'vxe-table--drag-row-line' + }), + h('div', { + ref: refDragColLineElem, + class: 'vxe-table--drag-col-line' + }), + h('div', { + ref: refDragTipElem, + class: 'vxe-table--drag-sort-tip' + }, renderDragTipContents()) + ]) + } + return renderEmptyElement($xeTable) + } + function handleUupdateResize () { const el = refElem.value if (el && el.clientWidth && el.clientHeight) { @@ -7314,7 +7566,7 @@ export default defineComponent({ const renderVN = () => { const { loading, stripe, showHeader, height, treeConfig, mouseConfig, showFooter, highlightCell, highlightHoverRow, highlightHoverColumn, editConfig, editRules } = props - const { isCalcColumn, isGroup, overflowX, overflowY, scrollXLoad, scrollYLoad, scrollbarHeight, tableData, tableColumn, tableGroupColumn, footerTableData, initStore, columnStore, filterStore, customStore, tooltipStore, dragRow, dragTipText } = reactData + const { isCalcColumn, isGroup, overflowX, overflowY, scrollXLoad, scrollYLoad, scrollbarHeight, tableData, tableColumn, tableGroupColumn, footerTableData, initStore, columnStore, filterStore, customStore, tooltipStore } = reactData const { leftList, rightList } = columnStore const loadingSlot = slots.loading const tipConfig = computeTipConfig.value @@ -7322,18 +7574,17 @@ export default defineComponent({ const checkboxOpts = computeCheckboxOpts.value const treeOpts = computeTreeOpts.value const rowOpts = computeRowOpts.value - const dragOpts = computeDragOpts.value const columnOpts = computeColumnOpts.value const vSize = computeSize.value const tableBorder = computeTableBorder.value const mouseOpts = computeMouseOpts.value + const areaOpts = computeAreaOpts.value const validTipOpts = computeValidTipOpts.value const loadingOpts = computeLoadingOpts.value const isMenu = computeIsMenu.value const currLoading = reactData._isLoading || loading const virtualScrollBars = computeVirtualScrollBars.value - const dragSlots = dragOpts.slots || {} - const rowTipSlot = dragSlots.rowTip + const isArea = mouseConfig && mouseOpts.area return h('div', { ref: refElem, class: ['vxe-table', 'vxe-table--render-default', `tid_${xID}`, `border--${tableBorder}`, { @@ -7343,7 +7594,9 @@ export default defineComponent({ 'old-cell-valid': editRules && getConfig().cellVaildMode === 'obsolete', 'cell--highlight': highlightCell, 'cell--selected': mouseConfig && mouseOpts.selected, - 'cell--area': mouseConfig && mouseOpts.area, + 'cell--area': isArea, + 'header-cell--area': isArea && areaOpts.selectCellByHeader, + 'body-cell--area': isArea && areaOpts.selectCellByBody, 'row--highlight': rowOpts.isHover || highlightHoverRow, 'column--highlight': columnOpts.isHover || highlightHoverColumn, 'checkbox--range': checkboxOpts.range, @@ -7552,16 +7805,9 @@ export default defineComponent({ }) : renderEmptyElement($xeTable), /** - * 拖拽提示 + * 拖拽排序提示 */ - rowOpts.drag && (dragRow || dragTipText) - ? h('div', { - ref: refRowDragTipElem, - class: 'vxe-table--row-drag-tip' - }, rowTipSlot - ? (dragRow ? callSlot(rowTipSlot, { row: dragRow }) : [renderEmptyElement($xeTable)]) - : (dragTipText ? [h('span', dragTipText)] : [renderEmptyElement($xeTable)])) - : renderEmptyElement($xeTable), + renderDragTip(), /** * 提示相关 */ @@ -7845,7 +8091,7 @@ export default defineComponent({ if (rowOpts.height && !props.showOverflow) { warnLog('vxe.error.notProp', ['table.show-overflow']) } - if (!$xeTable.handleUpdateCellAreas) { + if (!$xeTable.handleRecalculateCellAreas) { if (props.clipConfig) { warnLog('vxe.error.notProp', ['clip-config']) } @@ -7857,6 +8103,9 @@ export default defineComponent({ return } } + if (props.dragConfig) { + warnLog('vxe.error.delProp', ['drag-config', 'row-drag-config']) + } if (props.treeConfig && treeOpts.children) { warnLog('vxe.error.delProp', ['tree-config.children', 'tree-config.childrenField']) } diff --git a/packages/table/src/util.ts b/packages/table/src/util.ts index 7f54904c82..c8f8b25d7b 100644 --- a/packages/table/src/util.ts +++ b/packages/table/src/util.ts @@ -175,6 +175,16 @@ export function setCellValue (row: any, column: VxeTableDefines.ColumnInfo, valu return XEUtils.set(row, column.field, value) } +export function getRefElem (refEl: any) { + if (refEl) { + const rest = refEl.value + if (rest) { + return (rest.$el || rest) as HTMLElement + } + } + return null +} + /** * 列宽拖动最大宽度 * @param params diff --git a/packages/ui/index.ts b/packages/ui/index.ts index fda12ff086..ca29b368f7 100644 --- a/packages/ui/index.ts +++ b/packages/ui/index.ts @@ -43,8 +43,11 @@ VxeUI.setConfig({ // trigger: 'default' strict: true }, - dragConfig: { - showRowIcon: true + rowDragConfig: { + showIcon: true + }, + columnDragConfig: { + showIcon: true }, checkboxConfig: { // trigger: 'default', @@ -142,7 +145,8 @@ VxeUI.setConfig({ }, areaConfig: { autoClear: true, - selectCellByHeader: true + selectCellByHeader: true, + selectCellByBody: true }, clipConfig: { isCopy: true, @@ -241,6 +245,7 @@ VxeUI.setIcon({ TABLE_CUSTOM_SORT: iconPrefix + 'drag-handle', TABLE_MENU_OPTIONS: iconPrefix + 'arrow-right', TABLE_DRAG_ROW: iconPrefix + 'drag-handle', + TABLE_DRAG_COLUMN: iconPrefix + 'drag-handle', // toolbar TOOLBAR_TOOLS_REFRESH: iconPrefix + 'repeat', diff --git a/styles/components/table.scss b/styles/components/table.scss index 6cb8d8bdcf..3f0fff3f9d 100644 --- a/styles/components/table.scss +++ b/styles/components/table.scss @@ -663,9 +663,13 @@ } } } - &.cell--area { - .vxe-table--body-wrapper, - .vxe-body--column { + &.header-cell--area { + .vxe-table--header-wrapper { + user-select: none; + } + } + &.body-cell--area { + .vxe-table--body-wrapper { user-select: none; } } @@ -1077,6 +1081,7 @@ width: 1px; height: 100%; z-index: 9; + pointer-events: none; cursor: col-resize; &:before { content: ""; @@ -1237,7 +1242,32 @@ } } - /*拖拽行*/ + /*拖拽列*/ + .vxe-table--drag-col-line { + height: 100%; + width: 1px; + background-color: var(--vxe-ui-font-primary-color); + } + .vxe-header--column { + &.col--drag-origin { + & > .vxe-cell { + opacity: 0.5; + } + } + } + .vxe-header--col-list-move { + transition: transform 0.35s; + } + + .vxe-table--drag-col-line, + .vxe-table--drag-row-line { + display: none; + position: absolute; + top: 0; + left: 0; + z-index: 9; + pointer-events: none; + } .vxe-cell--drag-handle { user-select: none; & + span { @@ -1257,6 +1287,13 @@ cursor: not-allowed; } } + + /*拖拽行*/ + .vxe-table--drag-row-line { + width: 100%; + height: 1px; + background-color: var(--vxe-ui-font-primary-color); + } .vxe-body--row { &.row--drag-origin { & > .vxe-body--column { @@ -1265,41 +1302,11 @@ } } } - &.row--drag-active-target { - & > .vxe-body--column { - &::after { - display: none; - content: ""; - position: absolute; - left: 0; - width: 100%; - height: 2px; - background-color: var(--vxe-ui-font-primary-color); - z-index: 12; - } - } - &[drag-pos="top"] { - & > .vxe-body--column { - &::after { - display: block; - top: 0; - } - } - } - &[drag-pos="bottom"] { - & > .vxe-body--column { - &::after { - display: block; - bottom: 0; - } - } - } - } } .vxe-body--row-list-move { transition: transform 0.35s; } - .vxe-table--row-drag-tip { + .vxe-table--drag-sort-tip { display: none; position: absolute; top: 0;