diff --git a/examples/api/select.js b/examples/api/select.js index ca84247a2..c5635e17c 100644 --- a/examples/api/select.js +++ b/examples/api/select.js @@ -148,7 +148,7 @@ const apis = [ version: '', type: 'string', enum: '', - defVal: '默认 _XID,继承 setup.select.optionId', + defVal: '默认 _X_ID,继承 setup.select.optionId', list: [] }, { diff --git a/examples/api/table.js b/examples/api/table.js index 65210fe6c..81a7607bd 100644 --- a/examples/api/table.js +++ b/examples/api/table.js @@ -898,7 +898,7 @@ const apis = [ version: '', type: 'string', enum: '', - defVal: '默认 _XID,继承 setup.table.rowId', + defVal: '默认 _X_ID,继承 setup.table.rowId', list: [] }, { diff --git a/examples/views/table/start/Global.vue b/examples/views/table/start/Global.vue index 610a775ca..cfa8f6418 100644 --- a/examples/views/table/start/Global.vue +++ b/examples/views/table/start/Global.vue @@ -59,7 +59,7 @@ // menuConfig: { // visibleMethod () {} // }, - // rowId: '_XID', // 行数据的唯一主键字段名 + // rowId: '_X_ID', // 行数据的唯一主键字段名 // editConfig: { // mode: 'cell', // showAsterisk: true diff --git a/examples/views/table/tree/Basic.vue b/examples/views/table/tree/Basic.vue index 02d9b998f..b57c739c7 100644 --- a/examples/views/table/tree/Basic.vue +++ b/examples/views/table/tree/Basic.vue @@ -18,7 +18,7 @@ resizable border="inner" ref="xTree" - :tree-config="{transform: true}" + :tree-config="{children: 'childs'}" :data="tableData1" @toggle-tree-expand="toggleExpandChangeEvent"> @@ -85,24 +85,32 @@ export default { data () { return { tableData1: [ - { id: 10000, parentId: null, name: 'Test1', type: 'mp3', size: 1024, date: '2020-08-01' }, - { id: 10050, parentId: null, name: 'Test2', type: 'mp4', size: null, date: '2021-04-01' }, - { id: 24300, parentId: 10050, name: 'Test3', type: 'avi', size: 1024, date: '2020-03-01' }, - { id: 20045, parentId: 24300, name: 'Test4', type: 'html', size: 600, date: '2021-04-01' }, - { id: 10053, parentId: 24300, name: 'Test5', type: 'avi', size: null, date: '2021-04-01' }, - { id: 24330, parentId: 10053, name: 'Test6', type: 'txt', size: 25, date: '2021-10-01' }, - { id: 21011, parentId: 10053, name: 'Test7', type: 'pdf', size: 512, date: '2020-01-01' }, - { id: 22200, parentId: 10053, name: 'Test8', type: 'js', size: 1024, date: '2021-06-01' }, - { id: 23666, parentId: null, name: 'Test9', type: 'xlsx', size: 2048, date: '2020-11-01' }, - { id: 23677, parentId: 23666, name: 'Test10', type: 'js', size: 1024, date: '2021-06-01' }, - { id: 23671, parentId: 23677, name: 'Test11', type: 'js', size: 1024, date: '2021-06-01' }, - { id: 23672, parentId: 23677, name: 'Test12', type: 'js', size: 1024, date: '2021-06-01' }, - { id: 23688, parentId: 23666, name: 'Test13', type: 'js', size: 1024, date: '2021-06-01' }, - { id: 23681, parentId: 23688, name: 'Test14', type: 'js', size: 1024, date: '2021-06-01' }, - { id: 23682, parentId: 23688, name: 'Test15', type: 'js', size: 1024, date: '2021-06-01' }, - { id: 24555, parentId: null, name: 'Test16', type: 'avi', size: 224, date: '2020-10-01' }, - { id: 24566, parentId: 24555, name: 'Test17', type: 'js', size: 1024, date: '2021-06-01' }, - { id: 24577, parentId: 24555, name: 'Test18', type: 'js', size: 1024, date: '2021-06-01' } + { id: 1000, name: 'test abc1', type: 'mp3', size: 1024, date: '2020-08-01' }, + { + id: 1005, + name: 'Test2', + type: 'mp4', + size: null, + date: '2021-04-01', + childs: [ + { id: 24300, name: 'Test3', type: 'avi', size: 1024, date: '2020-03-01' }, + { id: 20045, name: 'test abc4', type: 'html', size: 600, date: '2021-04-01' }, + { + id: 10053, + name: 'test abc96', + type: 'avi', + size: null, + date: '2021-04-01', + childs: [ + { id: 24330, name: 'test abc5', type: 'txt', size: 25, date: '2021-10-01' }, + { id: 21011, name: 'Test6', type: 'pdf', size: 512, date: '2020-01-01' }, + { id: 22200, name: 'Test7', type: 'js', size: 1024, date: '2021-06-01' } + ] + } + ] + }, + { id: 23666, name: 'Test8', type: 'xlsx', size: 2048, date: '2020-11-01' }, + { id: 24555, name: 'test abc9', type: 'avi', size: 224, date: '2020-10-01' } ], tableData2: [ { id: 10000, parentId: null, name: 'Test1', type: 'mp3', size: 1024, date: '2020-08-01' }, diff --git a/examples/views/table/tree/Filter.vue b/examples/views/table/tree/Filter.vue index 520a11d0a..5fdec87fd 100644 --- a/examples/views/table/tree/Filter.vue +++ b/examples/views/table/tree/Filter.vue @@ -1,23 +1,17 @@ diff --git a/package.json b/package.json index c40a98157..a83c5d363 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vxe-table", - "version": "3.4.7", + "version": "3.4.7-beta.1", "description": "一个基于 vue 的 PC 端表格组件,支持增删改查、虚拟列表、虚拟树、懒加载、快捷菜单、数据校验、树形结构、打印导出、表单渲染、数据分页、弹窗、自定义模板、渲染器、贼灵活的配置项、扩展接口等...", "scripts": { "serve": "vue-cli-service serve", @@ -66,12 +66,12 @@ "vuex": "^3.4.0", "xe-ajax": "^4.0.5", "xe-clipboard": "^1.10.1", - "xe-utils": "^3.4.0", + "xe-utils": "^3.4.2", "xlsx": "^0.17.0" }, "peerDependencies": { "vue": "^2.6.0", - "xe-utils": "^3.2.0" + "xe-utils": "^3.4.2" }, "vetur": { "tags": "helper/vetur/tags.json", diff --git a/packages/edit/src/mixin.js b/packages/edit/src/mixin.js index 3d5fe2d7e..7a8610e39 100644 --- a/packages/edit/src/mixin.js +++ b/packages/edit/src/mixin.js @@ -6,12 +6,12 @@ import { browse } from '../../tools/src/dom' const { getRowid } = UtilTools function insertTreeRow (_vm, newRecords, isAppend) { - const { treeFullData, afterFullData, fullDataRowIdData, fullAllDataRowIdData, treeOpts } = _vm + const { tableFullTreeData, afterFullData, fullDataRowIdData, fullAllDataRowIdData, treeOpts } = _vm const funcName = isAppend ? 'push' : 'unshift' newRecords.forEach(item => { const parentRowId = item[treeOpts.parentField] const rowid = getRowid(_vm, item) - const matchObj = parentRowId ? XEUtils.findTree(treeFullData, item => parentRowId === item[treeOpts.rowField], treeOpts) : null + const matchObj = parentRowId ? XEUtils.findTree(tableFullTreeData, item => parentRowId === item[treeOpts.rowField], treeOpts) : null if (matchObj) { const { item: parentRow } = matchObj const parentRest = fullAllDataRowIdData[getRowid(_vm, parentRow)] @@ -31,13 +31,12 @@ function insertTreeRow (_vm, newRecords, isAppend) { } } afterFullData[funcName](item) - treeFullData[funcName](item) - const rest = { row: item, rowid, seq: -1, index: -1, _index: -1, $index: -1, items: treeFullData, parent: null, level: 0 } + tableFullTreeData[funcName](item) + const rest = { row: item, rowid, seq: -1, index: -1, _index: -1, $index: -1, items: tableFullTreeData, parent: null, level: 0 } fullDataRowIdData[rowid] = rest fullAllDataRowIdData[rowid] = rest } }) - _vm.updateVirtualTreeData() } export default { @@ -59,7 +58,7 @@ export default { * @param {Row} row 指定行 */ _insertAt (records, row) { - const { treeFullData, mergeList, afterFullData, editStore, sYOpts, scrollYLoad, tableFullData, treeConfig, fullDataRowIdData, fullAllDataRowIdData, treeOpts } = this + const { tableFullTreeData, mergeList, afterFullData, editStore, tableFullData, treeConfig, fullDataRowIdData, fullAllDataRowIdData, treeOpts } = this const { transform } = treeOpts if (!XEUtils.isArray(records)) { records = [records] @@ -99,7 +98,7 @@ export default { } else { // 如果为虚拟树 if (treeConfig && transform) { - const matchObj = XEUtils.findTree(treeFullData, item => row[treeOpts.rowField] === item[treeOpts.rowField], treeOpts) + const matchObj = XEUtils.findTree(tableFullTreeData, item => row[treeOpts.rowField] === item[treeOpts.rowField], treeOpts) if (matchObj) { const { parent: parentRow } = matchObj const parentChilds = matchObj.items @@ -122,7 +121,6 @@ export default { fullDataRowIdData[rowid] = rest fullAllDataRowIdData[rowid] = rest }) - this.updateVirtualTreeData() } else { if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') { UtilTools.warn('vxe.error.unableInsert') @@ -152,13 +150,12 @@ export default { } } editStore.insertList.unshift(...newRecords) - this.scrollYLoad = !treeConfig && sYOpts.gt > -1 && sYOpts.gt < tableFullData.length - this.handleTableData(transform) + this.handleTableData(treeConfig && treeOpts.transform) this.updateFooter() this.cacheRowMap() this.updateAfterDataIndex() this.checkSelectionStatus() - if (scrollYLoad) { + if (this.scrollYLoad) { this.updateScrollYSpace() } return this.$nextTick().then(() => { @@ -178,7 +175,7 @@ export default { * 如果为空则删除所有 */ _remove (rows) { - const { afterFullData, tableFullData, treeFullData, treeConfig, mergeList, editStore, checkboxOpts, selection, isInsertByRow, sYOpts, scrollYLoad, treeOpts } = this + const { afterFullData, tableFullData, tableFullTreeData, treeConfig, mergeList, editStore, checkboxOpts, selection, isInsertByRow, treeOpts } = this const { transform } = treeOpts const { actived, removeList, insertList } = editStore const { checkField: property } = checkboxOpts @@ -214,7 +211,7 @@ export default { if (treeConfig && transform) { rows.forEach((row) => { const rowid = getRowid(this, row) - const matchObj = XEUtils.findTree(treeFullData, item => rowid === getRowid(this, item), treeOpts) + const matchObj = XEUtils.findTree(tableFullTreeData, item => rowid === getRowid(this, item), treeOpts) if (matchObj) { const rItems = matchObj.items.splice(matchObj.index, 1) rest.push(rItems[0]) @@ -223,7 +220,6 @@ export default { if (afIndex > -1) { afterFullData.splice(afIndex, 1) } - this.updateVirtualTreeData() }) } else { rows.forEach(row => { @@ -259,13 +255,12 @@ export default { insertList.splice(iIndex, 1) } }) - this.scrollYLoad = !treeConfig && sYOpts.gt > -1 && sYOpts.gt < tableFullData.length - this.handleTableData(transform) + this.handleTableData(treeConfig && treeOpts.transform) this.updateFooter() this.cacheRowMap() this.updateAfterDataIndex() this.checkSelectionStatus() - if (scrollYLoad) { + if (this.scrollYLoad) { this.updateScrollYSpace() } return this.$nextTick().then(() => { @@ -318,7 +313,7 @@ export default { * 获取新增的临时数据 */ _getInsertRecords () { - const { treeConfig, treeFullData, tableFullData, treeOpts } = this + const { treeConfig, tableFullTreeData, tableFullData, treeOpts } = this const insertList = this.editStore.insertList const insertRecords = [] if (insertList.length) { @@ -326,7 +321,7 @@ export default { if (treeConfig && treeOpts.transform) { insertList.forEach(row => { const rowid = getRowid(this, row) - const matchObj = XEUtils.findTree(treeFullData, item => rowid === getRowid(this, item), treeOpts) + const matchObj = XEUtils.findTree(tableFullTreeData, item => rowid === getRowid(this, item), treeOpts) if (matchObj) { insertRecords.push(row) } diff --git a/packages/filter/src/mixin.js b/packages/filter/src/mixin.js index 3dc353fe9..6e8a24c25 100644 --- a/packages/filter/src/mixin.js +++ b/packages/filter/src/mixin.js @@ -104,7 +104,7 @@ export default { // 判断面板不能大于表格高度 let maxHeight = null if (filterHeight >= bodyElem.clientHeight) { - maxHeight = Math.max(40, bodyElem.clientHeight - (filterFootElem ? filterFootElem.offsetHeight : 0) - (filterHeadElem ? filterHeadElem.offsetHeight : 0)) + maxHeight = Math.max(60, bodyElem.clientHeight - (filterFootElem ? filterFootElem.offsetHeight : 0) - (filterHeadElem ? filterHeadElem.offsetHeight : 0)) } if (column.fixed === 'left') { left = targetElem.offsetLeft + targetElem.offsetParent.offsetLeft - centerWidth diff --git a/packages/select/src/select.js b/packages/select/src/select.js index 59a9e512e..a16828a4a 100644 --- a/packages/select/src/select.js +++ b/packages/select/src/select.js @@ -13,7 +13,7 @@ function getOptUniqueId () { } function getOptkey (_vm) { - return _vm.optionId || '_XID' + return _vm.optionId || '_X_ID' } function getOptid (_vm, option) { diff --git a/packages/table/src/body.js b/packages/table/src/body.js index ab3f22384..d919985e4 100644 --- a/packages/table/src/body.js +++ b/packages/table/src/body.js @@ -377,7 +377,7 @@ function renderRows (h, _vm, $xetable, fixedType, tableData, tableColumn) { ) } // 如果是树形表格 - if (treeConfig && !scrollYLoad && treeExpandeds.length) { + if (treeConfig && !scrollYLoad && !treeOpts.transform && treeExpandeds.length) { const rowChildren = row[treeOpts.children] if (rowChildren && rowChildren.length && treeExpandeds.indexOf(row) > -1) { rows.push(...renderRows(h, _vm, $xetable, fixedType, rowChildren, tableColumn)) diff --git a/packages/table/src/methods.js b/packages/table/src/methods.js index 798efd8b5..bcee9b73f 100644 --- a/packages/table/src/methods.js +++ b/packages/table/src/methods.js @@ -301,9 +301,33 @@ const Methods = { return this.handleTableData(true).then(this.updateFooter).then(this.recalculate) }, handleTableData (force) { - const { scrollYLoad, scrollYStore } = this - const fullData = force ? this.updateAfterFullData() : this.afterFullData - this.tableData = scrollYLoad ? fullData.slice(scrollYStore.startIndex, scrollYStore.endIndex) : fullData.slice(0) + const { treeConfig, scrollYLoad, scrollYStore, fullDataRowIdData, treeExpandeds, treeOpts } = this + let fullList = [] + // 是否进行数据处理 + if (force) { + this.updateAfterFullData() + } + // 如果为虚拟树,将树结构拍平 + if (treeConfig && treeOpts.transform) { + const expandMaps = new Map() + XEUtils.eachTree(this.afterTreeFullData, (row, index, items, path, parent) => { + if (!parent || (expandMaps.has(parent) && treeExpandeds.indexOf(parent) > -1)) { + expandMaps.set(row, 1) + fullList.push(row) + } + }, { children: treeOpts.mapChildren }) + } else { + fullList = this.afterFullData + } + const tableData = scrollYLoad ? fullList.slice(scrollYStore.startIndex, scrollYStore.endIndex) : fullList.slice(0) + tableData.forEach((row, $index) => { + const rowid = getRowid(this, row) + const rest = fullDataRowIdData[rowid] + if (rest) { + rest.$index = $index + } + }) + this.tableData = tableData return this.$nextTick() }, updateScrollYStatus (fullData) { @@ -334,13 +358,24 @@ const Methods = { if (!treeOpts.children) { UtilTools.error('vxe.error.reqProp', ['tree-config.children']) } + if (!treeOpts.mapChildren) { + UtilTools.error('vxe.error.reqProp', ['tree-config.mapChildren']) + } + if (treeOpts.children === treeOpts.mapChildren) { + UtilTools.error('vxe.error.errConflicts', ['tree-config.children', 'tree-config.mapChildren']) + } fullData.forEach(row => { if (row[treeOpts.children] && row[treeOpts.children].length) { UtilTools.warn('vxe.error.errConflicts', ['tree-config.transform', `row.${treeOpts.children}`]) } }) } - treeData = XEUtils.toArrayTree(fullData, { key: treeOpts.rowField, parentKey: treeOpts.parentField, children: treeOpts.children }) + treeData = XEUtils.toArrayTree(fullData, { + key: treeOpts.rowField, + parentKey: treeOpts.parentField, + children: treeOpts.children, + mapChildren: treeOpts.mapChildren + }) fullData = treeData.slice(0) } else { treeData = fullData.slice(0) @@ -356,7 +391,7 @@ const Methods = { this.scrollYLoad = sYLoad // 全量数据 this.tableFullData = fullData - this.treeFullData = treeData + this.tableFullTreeData = treeData // 缓存数据 this.cacheRowMap(true) // 原始数据 @@ -530,7 +565,7 @@ const Methods = { * 牺牲数据组装的耗时,用来换取使用过程中的流畅 */ cacheRowMap (source) { - const { treeConfig, treeOpts, tableFullData, fullDataRowMap, fullAllDataRowMap } = this + const { treeConfig, treeOpts, tableFullData, fullDataRowMap, fullAllDataRowMap, tableFullTreeData } = this let { fullDataRowIdData, fullAllDataRowIdData } = this const rowkey = getRowkey(this) const isLazy = treeConfig && treeOpts.lazy @@ -560,7 +595,7 @@ const Methods = { fullAllDataRowIdData = this.fullAllDataRowIdData = {} fullAllDataRowMap.clear() if (treeConfig) { - XEUtils.eachTree(tableFullData, handleCache, treeOpts) + XEUtils.eachTree(tableFullTreeData, handleCache, treeOpts) } else { tableFullData.forEach(handleCache) } @@ -1078,10 +1113,12 @@ const Methods = { * 如果存在筛选条件,继续处理 */ updateAfterFullData () { - const { tableFullColumn, tableFullData, filterOpts, sortOpts } = this + const { tableFullColumn, tableFullData, filterOpts, sortOpts, treeConfig, treeOpts, tableFullTreeData } = this const { remote: allRemoteFilter, filterMethod: allFilterMethod } = filterOpts const { remote: allRemoteSort, sortMethod: allSortMethod, multiple: sortMultiple } = sortOpts - let tableData = tableFullData.slice(0) + const { transform } = treeOpts + let tableData = [] + let tableTree = [] const filterColumns = [] const orderColumns = [] tableFullColumn.forEach(column => { @@ -1104,7 +1141,7 @@ const Methods = { } }) if (filterColumns.length) { - tableData = tableData.filter(row => { + const handleFilter = (row) => { return filterColumns.every(({ column, valueList, itemList }) => { if (valueList.length && !allRemoteFilter) { const { filterMethod, filterRender } = column @@ -1125,7 +1162,16 @@ const Methods = { } return true }) - }) + } + if (treeConfig && transform) { + tableTree = XEUtils.searchTree(tableFullTreeData, handleFilter, { ...treeOpts, original: true }) + } else { + tableData = treeConfig ? tableFullTreeData.filter(handleFilter) : tableFullData.filter(handleFilter) + tableTree = tableData + } + } else { + tableData = treeConfig ? tableFullTreeData.slice(0) : tableFullData.slice(0) + tableTree = tableData } const firstOrderColumn = orderColumns[0] if (!allRemoteSort && firstOrderColumn) { @@ -1145,18 +1191,20 @@ const Methods = { tableData = XEUtils.orderBy(tableData, sortByConfs || [firstOrderColumn].map(({ column, order }) => [getOrderField(this, column), order])) } } + tableTree = tableData } this.afterFullData = tableData - return tableData + this.afterTreeFullData = tableTree + this.updateAfterDataIndex() }, /** * 预编译 * 对渲染中的数据提前解析序号及索引。牺牲提前编译耗时换取渲染中额外损耗,使运行时更加流畅 */ updateAfterDataIndex () { - const { treeConfig, afterFullData, fullDataRowIdData, fullAllDataRowIdData, treeFullData, treeOpts } = this + const { treeConfig, afterFullData, fullDataRowIdData, fullAllDataRowIdData, afterTreeFullData, treeOpts } = this if (treeConfig) { - XEUtils.eachTree(treeFullData, (row, index, items, path) => { + XEUtils.eachTree(afterTreeFullData, (row, index, items, path) => { const rowid = getRowid(this, row) const allrest = fullAllDataRowIdData[rowid] const fullrest = fullDataRowIdData[rowid] @@ -3754,7 +3802,7 @@ const Methods = { return this.handleAsyncTreeExpandChilds(row) }).then(() => { if (transform) { - return this.updateVirtualTreeData() + return this.handleTableData() } }).then(() => { return this.recalculate() @@ -3900,23 +3948,6 @@ const Methods = { } return Promise.all(result).then(this.recalculate) }, - updateVirtualTreeData () { - const { scrollYLoad: oldScrollYLoad, treeExpandeds, treeOpts, treeFullData } = this - const fullData = [] - const expandMaps = new Map() - XEUtils.eachTree(treeFullData, (row, index, items, path, parent) => { - if (!parent || (expandMaps.has(parent) && treeExpandeds.indexOf(parent) > -1)) { - expandMaps.set(row, 1) - fullData.push(row) - } - }, treeOpts) - const scrollYLoad = this.updateScrollYStatus(fullData) - this.tableFullData = scrollYLoad ? fullData : treeFullData - if (scrollYLoad || oldScrollYLoad !== scrollYLoad) { - return this.handleTableData(true).then(() => this.recalculate()) - } - return this.$nextTick() - }, /** * 虚拟树的展开与收起 * @param rows @@ -3925,7 +3956,7 @@ const Methods = { */ handleVirtualTreeExpand (rows, expanded) { return this.handleBaseTreeExpand(rows, expanded).then(() => { - return this.updateVirtualTreeData() + return this.handleTableData() }).then(() => { return this.recalculate() }) @@ -3973,7 +4004,7 @@ const Methods = { if (reserve) { XEUtils.eachTree(tableFullData, row => this.handleTreeExpandReserve(row, false), treeOpts) } - return this.updateVirtualTreeData().then(() => { + return this.handleTableData().then(() => { if (isExists) { this.recalculate() } diff --git a/packages/tools/src/utils.js b/packages/tools/src/utils.js index 3e8e964bd..ff8bcb41e 100644 --- a/packages/tools/src/utils.js +++ b/packages/tools/src/utils.js @@ -183,7 +183,7 @@ export const UtilTools = { }, // 行主键 key getRowkey ($xetable) { - return $xetable.rowId || '_XID' + return $xetable.rowId || '_X_ID' }, // 行主键 value getRowid ($xetable, row) { diff --git a/packages/v-x-e-table/src/conf.js b/packages/v-x-e-table/src/conf.js index ba986c4b4..255c3e29e 100644 --- a/packages/v-x-e-table/src/conf.js +++ b/packages/v-x-e-table/src/conf.js @@ -49,7 +49,7 @@ export default { // storage: false, // checkMethod () {} // }, - // rowId: '_XID', // 行数据的唯一主键字段名 + // rowId: '_X_ID', // 行数据的唯一主键字段名 sortConfig: { // remote: false, // trigger: 'default', @@ -67,6 +67,7 @@ export default { parentField: 'parentId', children: 'children', hasChild: 'hasChild', + mapChildren: '_X_CHILD', indent: 20, showIcon: true },