vxe-table-select-area
Version:
一个基于 vxe-table 的可区域选中复制、粘贴的组件
1,564 lines (1,541 loc) • 173 kB
JavaScript
import XEUtils from 'xe-utils'
import GlobalConfig from '../../v-x-e-table/src/conf'
import Cell from './cell'
import VXETable from '../../v-x-e-table'
import { getRowid, getRowkey, clearTableAllStatus, handleFieldOrColumn, restoreScrollLocation, restoreScrollListener, toTreePathSeq, rowToVisible, colToVisible } from './util'
import UtilTools, { eqEmptyValue, isEnableConf, getFuncText } from '../../tools/utils'
import DomTools, { browse, getPaddingTopBottomSize, setScrollTop, setScrollLeft } from '../../tools/dom'
import { formats } from '../../v-x-e-table/src/formats'
import { warnLog, errLog } from '../../tools/log'
import { getSlotVNs } from '../../tools/vn'
const { setCellValue, hasChildrenList, getColumnList } = UtilTools
const { calcHeight, hasClass, addClass, removeClass, getEventTargetNode, isNodeElement } = DomTools
const isWebkit = browse['-webkit'] && !browse.edge
const debounceScrollYDuration = browse.msie ? 80 : 20
const resizableStorageKey = 'VXE_TABLE_CUSTOM_COLUMN_WIDTH'
const visibleStorageKey = 'VXE_TABLE_CUSTOM_COLUMN_VISIBLE'
const fixedStorageKey = 'VXE_TABLE_CUSTOM_COLUMN_FIXED'
const orderStorageKey = 'VXE_TABLE_CUSTOM_COLUMN_ORDER'
/**
* 生成行的唯一主键
*/
function getRowUniqueId () {
return XEUtils.uniqueId('row_')
}
function eqCellValue (row1, row2, field) {
const val1 = XEUtils.get(row1, field)
const val2 = XEUtils.get(row2, field)
if (eqEmptyValue(val1) && eqEmptyValue(val2)) {
return true
}
if (XEUtils.isString(val1) || XEUtils.isNumber(val1)) {
return ('' + val1) === ('' + val2)
}
return XEUtils.isEqual(val1, val2)
}
function getNextSortOrder (_vm, column) {
const orders = _vm.sortOpts.orders
const currOrder = column.order || null
const oIndex = orders.indexOf(currOrder) + 1
return orders[oIndex < orders.length ? oIndex : 0]
}
function getCustomStorageMap (key) {
const version = GlobalConfig.version
const rest = XEUtils.toStringJSON(localStorage.getItem(key))
return rest && rest._v === version ? rest : { _v: version }
}
function getRecoverRow (_vm, list) {
const { fullAllDataRowMap } = _vm
return list.filter(row => fullAllDataRowMap.has(row))
}
function handleReserveRow (_vm, reserveRowMap) {
const { fullDataRowIdData } = _vm
const reserveList = []
XEUtils.each(reserveRowMap, (item, rowid) => {
if (fullDataRowIdData[rowid] && reserveList.indexOf(fullDataRowIdData[rowid].row) === -1) {
reserveList.push(fullDataRowIdData[rowid].row)
}
})
return reserveList
}
function computeVirtualX (_vm) {
const { $refs, visibleColumn } = _vm
const { tableBody } = $refs
const tableBodyElem = tableBody ? tableBody.$el : null
if (tableBodyElem) {
const { scrollLeft, clientWidth } = tableBodyElem
const endWidth = scrollLeft + clientWidth
let toVisibleIndex = -1
let cWidth = 0
let visibleSize = 0
for (let colIndex = 0, colLen = visibleColumn.length; colIndex < colLen; colIndex++) {
cWidth += visibleColumn[colIndex].renderWidth
if (toVisibleIndex === -1 && scrollLeft < cWidth) {
toVisibleIndex = colIndex
}
if (toVisibleIndex >= 0) {
visibleSize++
if (cWidth > endWidth) {
break
}
}
}
return { toVisibleIndex: Math.max(0, toVisibleIndex), visibleSize: Math.max(8, visibleSize) }
}
return { toVisibleIndex: 0, visibleSize: 8 }
}
function computeVirtualY (_vm) {
const { $refs, vSize, rowHeightMaps } = _vm
const { tableHeader, tableBody } = $refs
const tableBodyElem = tableBody ? tableBody.$el : null
if (tableBodyElem) {
const tableHeaderElem = tableHeader ? tableHeader.$el : null
let rowHeight = 0
let firstTrElem
firstTrElem = tableBodyElem.querySelector('tr')
if (!firstTrElem && tableHeaderElem) {
firstTrElem = tableHeaderElem.querySelector('tr')
}
if (firstTrElem) {
rowHeight = firstTrElem.clientHeight
}
if (!rowHeight) {
rowHeight = rowHeightMaps[vSize || 'default']
}
const visibleSize = Math.max(8, Math.ceil(tableBodyElem.clientHeight / rowHeight) + 2)
return { rowHeight, visibleSize }
}
return { rowHeight: 0, visibleSize: 8 }
}
function calculateMergerOffserIndex (list, offsetItem, type) {
for (let mcIndex = 0, len = list.length; mcIndex < len; mcIndex++) {
const mergeItem = list[mcIndex]
const { startIndex, endIndex } = offsetItem
const mergeStartIndex = mergeItem[type]
const mergeSpanNumber = mergeItem[type + 'span']
const mergeEndIndex = mergeStartIndex + mergeSpanNumber
if (mergeStartIndex < startIndex && startIndex < mergeEndIndex) {
offsetItem.startIndex = mergeStartIndex
}
if (mergeStartIndex < endIndex && endIndex < mergeEndIndex) {
offsetItem.endIndex = mergeEndIndex
}
if (offsetItem.startIndex !== startIndex || offsetItem.endIndex !== endIndex) {
mcIndex = -1
}
}
}
function setMerges (_vm, merges, mList, rowList) {
if (merges) {
const { treeConfig, visibleColumn } = _vm
if (!XEUtils.isArray(merges)) {
merges = [merges]
}
if (treeConfig && merges.length) {
errLog('vxe.error.noTree', ['merge-cells | merge-footer-items'])
}
merges.forEach(item => {
let { row, col, rowspan, colspan } = item
if (rowList && XEUtils.isNumber(row)) {
row = rowList[row]
}
if (XEUtils.isNumber(col)) {
col = visibleColumn[col]
}
if ((rowList ? row : XEUtils.isNumber(row)) && col && (rowspan || colspan)) {
rowspan = XEUtils.toNumber(rowspan) || 1
colspan = XEUtils.toNumber(colspan) || 1
if (rowspan > 1 || colspan > 1) {
const mcIndex = XEUtils.findIndexOf(mList, item => item._row === row && item._col === col)
const mergeItem = mList[mcIndex]
if (mergeItem) {
mergeItem.rowspan = rowspan
mergeItem.colspan = colspan
mergeItem._rowspan = rowspan
mergeItem._colspan = colspan
} else {
const mergeRowIndex = rowList ? rowList.indexOf(row) : row
const mergeColIndex = visibleColumn.indexOf(col)
mList.push({
row: mergeRowIndex,
col: mergeColIndex,
rowspan,
colspan,
_row: row,
_col: col,
_rowspan: rowspan,
_colspan: colspan
})
}
}
}
})
}
}
function removeMerges (_vm, merges, mList, rowList) {
const rest = []
if (merges) {
const { treeConfig, visibleColumn } = _vm
if (!XEUtils.isArray(merges)) {
merges = [merges]
}
if (treeConfig && merges.length) {
errLog('vxe.error.noTree', ['merge-cells | merge-footer-items'])
}
merges.forEach(item => {
let { row, col } = item
if (rowList && XEUtils.isNumber(row)) {
row = rowList[row]
}
if (XEUtils.isNumber(col)) {
col = visibleColumn[col]
}
const mcIndex = XEUtils.findIndexOf(mList, item => item._row === row && item._col === col)
if (mcIndex > -1) {
const rItems = mList.splice(mcIndex, 1)
rest.push(rItems[0])
}
})
}
return rest
}
function clearAllSort (_vm) {
_vm.tableFullColumn.forEach((column) => {
column.order = null
})
}
function getOrderField (_vm, column) {
const { sortBy, sortType } = column
return (row) => {
let cellValue
if (sortBy) {
cellValue = XEUtils.isFunction(sortBy) ? sortBy({ row, column }) : XEUtils.get(row, sortBy)
} else {
cellValue = _vm.getCellLabel(row, column)
}
if (!sortType || sortType === 'auto') {
return isNaN(cellValue) ? cellValue : XEUtils.toNumber(cellValue)
} else if (sortType === 'number') {
return XEUtils.toNumber(cellValue)
} else if (sortType === 'string') {
return XEUtils.toValueString(cellValue)
}
return cellValue
}
}
const Methods = {
callSlot (slotFunc, params, h, vNodes) {
if (slotFunc) {
const { $xegrid } = this
if ($xegrid) {
return $xegrid.callSlot(slotFunc, params, h, vNodes)
}
if (XEUtils.isFunction(slotFunc)) {
return getSlotVNs(slotFunc.call(this, params, h, vNodes))
}
}
return []
},
/**
* 获取父容器元素
*/
getParentElem () {
const { $el, $xegrid } = this
return $xegrid ? $xegrid.$el.parentNode : $el.parentNode
},
/**
* 获取父容器的高度
*/
getParentHeight () {
const { $el, $xegrid, height } = this
const parentElem = $el.parentNode
const parentPaddingSize = height === 'auto' ? getPaddingTopBottomSize(parentElem) : 0
return Math.floor($xegrid ? $xegrid.getParentHeight() : XEUtils.toNumber(getComputedStyle(parentElem).height) - parentPaddingSize)
},
/**
* 获取需要排除的高度
* 但渲染表格高度时,需要排除工具栏或分页等相关组件的高度
* 如果存在表尾合计滚动条,则需要排除滚动条高度
*/
getExcludeHeight () {
const { $xegrid } = this
return $xegrid ? $xegrid.getExcludeHeight() : 0
},
/**
* 重置表格的一切数据状态
*/
clearAll () {
return clearTableAllStatus(this)
},
/**
* 同步 data 数据(即将废弃)
* 如果用了该方法,那么组件将不再记录增删改的状态,只能自行实现对应逻辑
* 对于某些特殊的场景,比如深层树节点元素发生变动时可能会用到
*/
syncData () {
return this.$nextTick().then(() => {
this.tableData = []
return this.$nextTick().then(() => this.loadTableData(this.tableFullData))
})
},
/**
* 手动处理数据,用于手动排序与筛选
* 对于手动更改了排序、筛选...等条件后需要重新处理数据时可能会用到
*/
updateData () {
const { scrollXLoad, scrollYLoad } = this
return this.handleTableData(true).then(() => {
this.updateFooter()
this.checkSelectionStatus()
if (scrollXLoad || scrollYLoad) {
if (scrollXLoad) {
this.updateScrollXSpace()
}
if (scrollYLoad) {
this.updateScrollYSpace()
}
return this.refreshScroll()
}
}).then(() => {
this.updateCellAreas()
return this.recalculate(true)
}).then(() => {
// 存在滚动行为未结束情况
setTimeout(() => this.recalculate(), 50)
})
},
handleTableData (force) {
const { scrollYLoad, scrollYStore, fullDataRowIdData, afterFullData } = this
let fullList = afterFullData
// 是否进行数据处理
if (force) {
// 更新数据,处理筛选和排序
this.updateAfterFullData()
// 如果为虚拟树,将树结构拍平
fullList = this.handleVirtualTreeToList()
}
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) {
const { treeConfig, treeOpts, sYOpts } = this
const { transform } = treeOpts
const allList = fullData || this.tableFullData
// 如果gt为0,则总是启用
const scrollYLoad = (transform || !treeConfig) && !!sYOpts.enabled && sYOpts.gt > -1 && (sYOpts.gt === 0 || sYOpts.gt <= allList.length)
this.scrollYLoad = scrollYLoad
return scrollYLoad
},
/**
* 加载表格数据
* @param {Array} datas 数据
*/
loadTableData (datas) {
const { keepSource, treeConfig, treeOpts, editStore, scrollYStore, scrollXStore, lastScrollLeft, lastScrollTop, scrollYLoad: oldScrollYLoad, sXOpts, sYOpts } = this
let treeData = []
let fullData = datas ? datas.slice(0) : []
if (treeConfig) {
// 树结构自动转换
if (treeOpts.transform) {
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
if (!treeOpts.rowField) {
errLog('vxe.error.reqProp', ['table.tree-config.rowField'])
}
if (!treeOpts.parentField) {
errLog('vxe.error.reqProp', ['table.tree-config.parentField'])
}
if (!treeOpts.children) {
errLog('vxe.error.reqProp', ['tree-config.children'])
}
if (!treeOpts.mapChildren) {
errLog('vxe.error.reqProp', ['tree-config.mapChildren'])
}
if (treeOpts.children === treeOpts.mapChildren) {
errLog('vxe.error.errConflicts', ['tree-config.children', 'tree-config.mapChildren'])
}
fullData.forEach(row => {
if (row[treeOpts.children] && row[treeOpts.children].length) {
warnLog('vxe.error.errConflicts', ['tree-config.transform', `row.${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)
}
}
scrollYStore.startIndex = 0
scrollYStore.endIndex = 1
scrollXStore.startIndex = 0
scrollXStore.endIndex = 1
editStore.insertList = []
editStore.insertMaps = {}
editStore.removeList = []
editStore.removeMaps = {}
const sYLoad = this.updateScrollYStatus(fullData)
this.scrollYLoad = sYLoad
// 全量数据
this.tableFullData = fullData
this.tableFullTreeData = treeData
// 缓存数据
this.cacheRowMap(true)
// 原始数据
this.tableSynchData = datas
// 克隆原数据,用于显示编辑状态,与编辑值做对比
if (keepSource) {
this.tableSourceData = XEUtils.clone(fullData, true)
}
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
if (sYLoad) {
if (!(this.height || this.maxHeight)) {
errLog('vxe.error.reqProp', ['table.height | table.max-height | table.scroll-y={enabled: false}'])
}
if (!this.showOverflow) {
warnLog('vxe.error.reqProp', ['table.show-overflow'])
}
if (this.spanMethod) {
warnLog('vxe.error.scrollErrProp', ['table.span-method'])
}
}
}
if (this.clearCellAreas && this.mouseConfig) {
this.clearCellAreas()
this.clearCopyCellArea()
}
this.clearMergeCells()
this.clearMergeFooterItems()
this.handleTableData(true)
this.updateFooter()
return this.$nextTick().then(() => {
this.updateHeight()
this.updateStyle()
}).then(() => {
this.computeScrollLoad()
}).then(() => {
// 是否启用了虚拟滚动
if (sYLoad) {
scrollYStore.endIndex = scrollYStore.visibleSize
}
this.handleReserveStatus()
this.checkSelectionStatus()
return new Promise(resolve => {
this.$nextTick()
.then(() => this.recalculate())
.then(() => {
let targetScrollLeft = lastScrollLeft
let targetScrollTop = lastScrollTop
// 是否在更新数据之后自动滚动重置滚动条
if (sXOpts.scrollToLeftOnChange) {
targetScrollLeft = 0
}
if (sYOpts.scrollToTopOnChange) {
targetScrollTop = 0
}
// 是否变更虚拟滚动
if (oldScrollYLoad === sYLoad) {
restoreScrollLocation(this, targetScrollLeft, targetScrollTop).then(resolve)
} else {
setTimeout(() => restoreScrollLocation(this, targetScrollLeft, targetScrollTop).then(resolve))
}
})
})
})
},
/**
* 重新加载数据,不会清空表格状态
* @param {Array} datas 数据
*/
loadData (datas) {
const { inited, initStatus } = this
return this.loadTableData(datas).then(() => {
this.inited = true
this.initStatus = true
if (!initStatus) {
this.handleLoadDefaults()
}
if (!inited) {
this.handleInitDefaults()
}
return this.recalculate()
})
},
/**
* 重新加载数据,会清空表格状态
* @param {Array} datas 数据
*/
reloadData (datas) {
const { inited } = this
return this.clearAll()
.then(() => {
this.inited = true
this.initStatus = true
return this.loadTableData(datas)
})
.then(() => {
this.handleLoadDefaults()
if (!inited) {
this.handleInitDefaults()
}
return this.recalculate()
})
},
/**
* 局部加载行数据并恢复到初始状态
* 对于行数据需要局部更改的场景中可能会用到
* @param {Row} row 行对象
* @param {Object} record 新数据
* @param {String} field 字段名
*/
reloadRow (row, record, field) {
const { keepSource, tableSourceData, tableData } = this
if (keepSource) {
const rowIndex = this.getRowIndex(row)
const oRow = tableSourceData[rowIndex]
if (oRow && row) {
if (field) {
const newValue = XEUtils.get(record || row, field)
XEUtils.set(row, field, newValue)
XEUtils.set(oRow, field, newValue)
} else {
const newRecord = XEUtils.clone({ ...record }, true)
XEUtils.destructuring(oRow, Object.assign(row, newRecord))
}
}
this.tableData = tableData.slice(0)
} else {
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
warnLog('vxe.error.reqProp', ['keep-source'])
}
}
return this.$nextTick()
},
/**
* 加载列配置
* 对于表格列需要重载、局部递增场景下可能会用到
* @param {ColumnInfo} columns 列配置
*/
loadColumn (columns) {
const collectColumn = XEUtils.mapTree(columns, column => Cell.createColumn(this, column), { children: 'children' })
return this.handleColumn(collectColumn)
},
/**
* 加载列配置并恢复到初始状态
* 对于表格列需要重载、局部递增场景下可能会用到
* @param {ColumnInfo} columns 列配置
*/
reloadColumn (columns) {
return this.clearAll().then(() => {
return this.loadColumn(columns)
})
},
handleColumn (collectColumn) {
this.collectColumn = collectColumn
const tableFullColumn = getColumnList(collectColumn)
this.tableFullColumn = tableFullColumn
this.cacheColumnMap()
this.restoreCustomStorage()
this.parseColumns().then(() => {
if (this.scrollXLoad) {
this.loadScrollXData(true)
}
})
this.clearMergeCells()
this.clearMergeFooterItems()
this.handleTableData(true)
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
if ((this.scrollXLoad || this.scrollYLoad) && this.expandColumn) {
warnLog('vxe.error.scrollErrProp', ['column.type=expand'])
}
}
return this.$nextTick().then(() => {
if (this.$toolbar) {
this.$toolbar.syncUpdate({ collectColumn, $table: this })
}
return this.recalculate()
})
},
/**
* 更新数据行的 Map
* 牺牲数据组装的耗时,用来换取使用过程中的流畅
*/
cacheRowMap (source) {
const { treeConfig, treeOpts, tableFullData, fullDataRowMap, fullAllDataRowMap, tableFullTreeData } = this
let { fullDataRowIdData, fullAllDataRowIdData } = this
const rowkey = getRowkey(this)
const isLazy = treeConfig && treeOpts.lazy
const handleCache = (row, index, items, path, parent, nodes) => {
let rowid = getRowid(this, row)
const seq = treeConfig && path ? toTreePathSeq(path) : index + 1
const level = nodes ? nodes.length - 1 : 0
if (eqEmptyValue(rowid)) {
rowid = getRowUniqueId()
XEUtils.set(row, rowkey, rowid)
}
if (isLazy && row[treeOpts.hasChild] && XEUtils.isUndefined(row[treeOpts.children])) {
row[treeOpts.children] = null
}
const rest = { row, rowid, seq, index: treeConfig && parent ? -1 : index, _index: -1, $index: -1, items, parent, level }
if (source) {
fullDataRowIdData[rowid] = rest
fullDataRowMap.set(row, rest)
}
fullAllDataRowIdData[rowid] = rest
fullAllDataRowMap.set(row, rest)
}
if (source) {
fullDataRowIdData = this.fullDataRowIdData = {}
fullDataRowMap.clear()
}
fullAllDataRowIdData = this.fullAllDataRowIdData = {}
fullAllDataRowMap.clear()
if (treeConfig) {
XEUtils.eachTree(tableFullTreeData, handleCache, treeOpts)
} else {
tableFullData.forEach(handleCache)
}
},
loadTreeChildren (row, childRecords) {
const { keepSource, tableSourceData, treeOpts, fullDataRowIdData, fullDataRowMap, fullAllDataRowMap, fullAllDataRowIdData } = this
const { transform, children, mapChildren } = treeOpts
const rest = fullAllDataRowIdData[getRowid(this, row)]
const parentLevel = rest ? rest.level : 0
return this.createData(childRecords).then((rows) => {
if (keepSource) {
const rowid = getRowid(this, row)
const matchObj = XEUtils.findTree(tableSourceData, (item) => rowid === getRowid(this, item), treeOpts)
if (matchObj) {
matchObj.item[children] = XEUtils.clone(rows, true)
}
}
XEUtils.eachTree(rows, (childRow, index, items, path, parent, nodes) => {
const rowid = getRowid(this, childRow)
const rest = { row: childRow, rowid, seq: -1, index, _index: -1, $index: -1, items, parent, level: parentLevel + nodes.length }
fullDataRowIdData[rowid] = rest
fullDataRowMap.set(childRow, rest)
fullAllDataRowIdData[rowid] = rest
fullAllDataRowMap.set(childRow, rest)
}, treeOpts)
row[children] = rows
if (transform) {
row[mapChildren] = rows
}
this.updateAfterDataIndex()
return rows
})
},
/**
* 更新数据列的 Map
* 牺牲数据组装的耗时,用来换取使用过程中的流畅
*/
cacheColumnMap () {
const { tableFullColumn, collectColumn, fullColumnMap, showOverflow, columnOpts, rowOpts } = this
const fullColumnIdData = this.fullColumnIdData = {}
const fullColumnFieldData = this.fullColumnFieldData = {}
const isGroup = collectColumn.some(hasChildrenList)
let isAllOverflow = !!showOverflow
let expandColumn
let treeNodeColumn
let checkboxColumn
let radioColumn
let htmlColumn
let hasFixed
const handleFunc = (column, index, items, path, parent) => {
const { id: colid, field, fixed, type, treeNode } = column
const rest = { column, colid, index, items, parent }
if (field) {
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
if (fullColumnFieldData[field]) {
warnLog('vxe.error.colRepet', ['field', field])
}
}
fullColumnFieldData[field] = rest
}
if (!hasFixed && fixed) {
hasFixed = fixed
}
if (!htmlColumn && type === 'html') {
htmlColumn = column
}
if (treeNode) {
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
if (treeNodeColumn) {
warnLog('vxe.error.colRepet', ['tree-node', treeNode])
}
}
if (!treeNodeColumn) {
treeNodeColumn = column
}
} else if (type === 'expand') {
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
if (expandColumn) {
warnLog('vxe.error.colRepet', ['type', type])
}
}
if (!expandColumn) {
expandColumn = column
}
}
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
if (type === 'checkbox') {
if (checkboxColumn) {
warnLog('vxe.error.colRepet', ['type', type])
}
if (!checkboxColumn) {
checkboxColumn = column
}
} else if (type === 'radio') {
if (radioColumn) {
warnLog('vxe.error.colRepet', ['type', type])
}
if (!radioColumn) {
radioColumn = column
}
}
}
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
if (this.showOverflow && column.showOverflow === false) {
warnLog('vxe.error.errConflicts', [`table.show-overflow=${this.showOverflow}`, `column.show-overflow=${column.showOverflow}`])
}
if (this.showHeaderOverflow && column.showHeaderOverflow === false) {
warnLog('vxe.error.errConflicts', [`table.show-header-overflow=${this.showHeaderOverflow}`, `column.show-header-overflow=${column.showHeaderOverflow}`])
}
if (this.showFooterOverflow && column.showFooterOverflow === false) {
warnLog('vxe.error.errConflicts', [`table.show-footer-overflow=${this.showFooterOverflow}`, `column.show-footer-overflow=${column.showFooterOverflow}`])
}
}
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
if (htmlColumn) {
if (!columnOpts.useKey) {
errLog('vxe.error.reqProp', ['column-config.useKey', 'column.type=html'])
}
if (!rowOpts.useKey) {
errLog('vxe.error.reqProp', ['row-config.useKey', 'column.type=html'])
}
}
}
if (isAllOverflow && column.showOverflow === false) {
isAllOverflow = false
}
if (fullColumnIdData[colid]) {
errLog('vxe.error.colRepet', ['colId', colid])
}
fullColumnIdData[colid] = rest
fullColumnMap.set(column, rest)
}
fullColumnMap.clear()
if (isGroup) {
XEUtils.eachTree(collectColumn, (column, index, items, path, parent, nodes) => {
column.level = nodes.length
handleFunc(column, index, items, path, parent)
})
} else {
tableFullColumn.forEach(handleFunc)
}
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
if (expandColumn && this.mouseOpts.area) {
errLog('vxe.error.errConflicts', ['mouse-config.area', 'column.type=expand'])
}
}
this.isGroup = isGroup
this.treeNodeColumn = treeNodeColumn
this.expandColumn = expandColumn
this.isAllOverflow = isAllOverflow
},
/**
* 根据 tr 元素获取对应的 row 信息
* @param {Element} tr 元素
*/
getRowNode (tr) {
if (tr) {
const { fullAllDataRowIdData } = this
const rowid = tr.getAttribute('rowid')
const rest = fullAllDataRowIdData[rowid]
if (rest) {
return { rowid: rest.rowid, item: rest.row, index: rest.index, items: rest.items, parent: rest.parent }
}
}
return null
},
/**
* 根据 th/td 元素获取对应的 column 信息
* @param {Element} cell 元素
*/
getColumnNode (cell) {
if (cell) {
const { fullColumnIdData } = this
const colid = cell.getAttribute('colid')
const rest = fullColumnIdData[colid]
if (rest) {
return { colid: rest.colid, item: rest.column, index: rest.index, items: rest.items, parent: rest.parent }
}
}
return null
},
/**
* 根据 row 获取序号
* @param {Row} row 行对象
*/
getRowSeq (row) {
const { fullDataRowIdData } = this
if (row) {
const rowid = getRowid(this, row)
const rest = fullDataRowIdData[rowid]
if (rest) {
return rest.seq
}
}
return -1
},
/**
* 根据 row 获取相对于 data 中的索引
* @param {Row} row 行对象
*/
getRowIndex (row) {
return this.fullDataRowMap.has(row) ? this.fullDataRowMap.get(row).index : -1
},
/**
* 根据 row 获取相对于当前数据中的索引
* @param {Row} row 行对象
*/
getVTRowIndex (row) {
return this.afterFullData.indexOf(row)
},
// 在 v3 中废弃
_getRowIndex (row) {
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
warnLog('vxe.error.delFunc', ['_getRowIndex', 'getVTRowIndex'])
}
return this.getVTRowIndex(row)
},
/**
* 根据 row 获取渲染中的虚拟索引
* @param {Row} row 行对象
*/
getVMRowIndex (row) {
return this.tableData.indexOf(row)
},
// 在 v3 中废弃
$getRowIndex (row) {
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
warnLog('vxe.error.delFunc', ['$getRowIndex', 'getVMRowIndex'])
}
return this.getVMRowIndex(row)
},
/**
* 根据 column 获取相对于 columns 中的索引
* @param {ColumnInfo} column 列配置
*/
getColumnIndex (column) {
return this.fullColumnMap.has(column) ? this.fullColumnMap.get(column).index : -1
},
/**
* 根据 column 获取相对于当前表格列中的索引
* @param {ColumnInfo} column 列配置
*/
getVTColumnIndex (column) {
return this.visibleColumn.indexOf(column)
},
// 在 v3 中废弃
_getColumnIndex (column) {
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
warnLog('vxe.error.delFunc', ['_getColumnIndex', 'getVTColumnIndex'])
}
return this.getVTColumnIndex(column)
},
/**
* 根据 column 获取渲染中的虚拟索引
* @param {ColumnInfo} column 列配置
*/
getVMColumnIndex (column) {
return this.tableColumn.indexOf(column)
},
// 在 v3 中废弃
$getColumnIndex (column) {
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
warnLog('vxe.error.delFunc', ['$getColumnIndex', 'getVMColumnIndex'])
}
return this.getVMColumnIndex(column)
},
/**
* 判断是否为索引列
* @param {ColumnInfo} column 列配置
*/
isSeqColumn (column) {
return column && column.type === 'seq'
},
/**
* 定义行数据中的列属性,如果不存在则定义
* @param {Row} records 行数据
*/
defineField (records) {
const { radioOpts, checkboxOpts, treeConfig, treeOpts, expandOpts } = this
const rowkey = getRowkey(this)
if (!XEUtils.isArray(records)) {
records = [records || {}]
}
return records.map(record => {
this.tableFullColumn.forEach(column => {
const { field, editRender } = column
if (field && !XEUtils.has(record, field)) {
let cellValue = null
if (editRender) {
const { defaultValue } = editRender
if (XEUtils.isFunction(defaultValue)) {
cellValue = defaultValue({ column })
} else if (!XEUtils.isUndefined(defaultValue)) {
cellValue = defaultValue
}
}
XEUtils.set(record, field, cellValue)
}
})
const otherFields = [radioOpts.labelField, checkboxOpts.checkField, checkboxOpts.labelField, expandOpts.labelField]
otherFields.forEach((key) => {
if (key && eqEmptyValue(XEUtils.get(record, key))) {
XEUtils.set(record, key, null)
}
})
if (treeConfig && treeOpts.lazy && XEUtils.isUndefined(record[treeOpts.children])) {
record[treeOpts.children] = null
}
// 必须有行数据的唯一主键,可以自行设置;也可以默认生成一个随机数
if (eqEmptyValue(XEUtils.get(record, rowkey))) {
XEUtils.set(record, rowkey, getRowUniqueId())
}
return record
})
},
/**
* 创建 data 对象
* 对于某些特殊场景可能会用到,会自动对数据的字段名进行检测,如果不存在就自动定义
* @param {Array} records 新数据
*/
createData (records) {
return this.$nextTick().then(() => {
return this.defineField(records)
})
},
/**
* 创建 Row|Rows 对象
* 对于某些特殊场景需要对数据进行手动插入时可能会用到
* @param {Array/Object} records 新数据
*/
createRow (records) {
const isArr = XEUtils.isArray(records)
if (!isArr) {
records = [records]
}
return this.createData(records).then(rows => isArr ? rows : rows[0])
},
/**
* 还原数据
* 如果不传任何参数,则还原整个表格
* 如果传 row 则还原一行
* 如果传 rows 则还原多行
* 如果还额外传了 field 则还原指定的单元格数据
*/
revertData (rows, field) {
const { keepSource, tableSourceData, treeConfig } = this
if (!keepSource) {
if (process.env.VUE_APP_VXE_TABLE_ENV === 'development') {
warnLog('vxe.error.reqProp', ['keep-source'])
}
return this.$nextTick()
}
let targetRows = rows
if (rows) {
if (!XEUtils.isArray(rows)) {
targetRows = [rows]
}
} else {
targetRows = XEUtils.toArray(this.getUpdateRecords())
}
if (targetRows.length) {
targetRows.forEach(row => {
if (!this.isInsertByRow(row)) {
const rowIndex = this.getRowIndex(row)
if (treeConfig && rowIndex === -1) {
errLog('vxe.error.noTree', ['revertData'])
}
const oRow = tableSourceData[rowIndex]
if (oRow && row) {
if (field) {
XEUtils.set(row, field, XEUtils.clone(XEUtils.get(oRow, field), true))
} else {
XEUtils.destructuring(row, XEUtils.clone(oRow, true))
}
}
}
})
}
if (rows) {
return this.$nextTick()
}
return this.reloadData(tableSourceData)
},
/**
* 清空单元格内容
* 如果不创参数,则清空整个表格内容
* 如果传 row 则清空一行内容
* 如果传 rows 则清空多行内容
* 如果还额外传了 field 则清空指定单元格内容
* @param {Array/Row} rows 行数据
* @param {String} field 字段名
*/
clearData (rows, field) {
const { tableFullData, visibleColumn } = this
if (!arguments.length) {
rows = tableFullData
} else if (rows && !XEUtils.isArray(rows)) {
rows = [rows]
}
if (field) {
rows.forEach(row => XEUtils.set(row, field, null))
} else {
rows.forEach(row => {
visibleColumn.forEach(column => {
if (column.field) {
setCellValue(row, column, null)
}
})
})
}
return this.$nextTick()
},
/**
* 检查是否为临时行数据
* @param {Row} row 行对象
*/
isInsertByRow (row) {
const { editStore } = this
const rowid = getRowid(this, row)
return editStore.insertList.length && editStore.insertMaps[rowid]
},
/**
* 删除所有新增的临时数据
* @returns
*/
removeInsertRow () {
return this.remove(this.editStore.insertList)
},
/**
* 检查行或列数据是否发生改变
* @param {Row} row 行对象
* @param {String} field 字段名
*/
isUpdateByRow (row, field) {
const { visibleColumn, keepSource, treeConfig, treeOpts, tableSourceData, fullDataRowIdData } = this
if (keepSource) {
let oRow, property
const rowid = getRowid(this, row)
// 新增的数据不需要检测
if (!fullDataRowIdData[rowid]) {
return false
}
if (treeConfig) {
const children = treeOpts.children
const matchObj = XEUtils.findTree(tableSourceData, item => rowid === getRowid(this, item), treeOpts)
row = Object.assign({}, row, { [children]: null })
if (matchObj) {
oRow = Object.assign({}, matchObj.item, { [children]: null })
}
} else {
const oRowIndex = fullDataRowIdData[rowid].index
oRow = tableSourceData[oRowIndex]
}
if (oRow) {
if (arguments.length > 1) {
return !eqCellValue(oRow, row, field)
}
for (let index = 0, len = visibleColumn.length; index < len; index++) {
property = visibleColumn[index].field
if (property && !eqCellValue(oRow, row, property)) {
return true
}
}
}
}
return false
},
/**
* 获取表格的可视列,也可以指定索引获取列
* @param {Number} columnIndex 索引
*/
getColumns (columnIndex) {
const columns = this.visibleColumn
return XEUtils.isUndefined(columnIndex) ? columns.slice(0) : columns[columnIndex]
},
/**
* 根据列的唯一主键获取列
* @param {String} colid 列主键
*/
getColumnById (colid) {
const fullColumnIdData = this.fullColumnIdData
return fullColumnIdData[colid] ? fullColumnIdData[colid].column : null
},
/**
* 根据列的字段名获取列
* @param {String} field 字段名
*/
getColumnByField (field) {
const fullColumnFieldData = this.fullColumnFieldData
return fullColumnFieldData[field] ? fullColumnFieldData[field].column : null
},
/**
* 获取当前表格的列
* 收集到的全量列、全量表头列、处理条件之后的全量表头列、当前渲染中的表头列
*/
getTableColumn () {
return {
collectColumn: this.collectColumn.slice(0),
fullColumn: this.tableFullColumn.slice(0),
visibleColumn: this.visibleColumn.slice(0),
tableColumn: this.tableColumn.slice(0)
}
},
/**
* 获取数据,和 data 的行为一致,也可以指定索引获取数据
*/
getData (rowIndex) {
const tableSynchData = this.data || this.tableSynchData
return XEUtils.isUndefined(rowIndex) ? tableSynchData.slice(0) : tableSynchData[rowIndex]
},
/**
* 用于多选行,获取已选中的数据
*/
getCheckboxRecords (isFull) {
const { tableFullData, afterFullData, treeConfig, treeOpts, checkboxOpts, tableFullTreeData, afterTreeFullData } = this
const { transform, children, mapChildren } = treeOpts
const { checkField } = checkboxOpts
const currTableData = isFull ? (transform ? tableFullTreeData : tableFullData) : (transform ? afterTreeFullData : afterFullData)
let rowList = []
if (checkField) {
if (treeConfig) {
rowList = XEUtils.filterTree(currTableData, row => XEUtils.get(row, checkField), { children: transform ? mapChildren : children })
} else {
rowList = currTableData.filter(row => XEUtils.get(row, checkField))
}
} else {
const { selection } = this
if (treeConfig) {
rowList = XEUtils.filterTree(currTableData, row => this.findRowIndexOf(selection, row) > -1, { children: transform ? mapChildren : children })
} else {
rowList = currTableData.filter(row => this.findRowIndexOf(selection, row) > -1)
}
}
return rowList
},
/**
* 如果为虚拟树,将树结构拍平
* @returns
*/
handleVirtualTreeToList () {
const { treeOpts, treeConfig, treeExpandeds, afterTreeFullData, afterFullData } = this
if (treeConfig && treeOpts.transform) {
const fullData = []
const expandMaps = new Map()
XEUtils.eachTree(afterTreeFullData, (row, index, items, path, parent) => {
if (!parent || (expandMaps.has(parent) && treeExpandeds.indexOf(parent) > -1)) {
expandMaps.set(row, 1)
fullData.push(row)
}
}, { children: treeOpts.mapChildren })
this.afterFullData = fullData
this.updateScrollYStatus(fullData)
return fullData
}
return afterFullData
},
/**
* 获取处理后全量的表格数据
* 如果存在筛选条件,继续处理
*/
updateAfterFullData () {
const { tableFullColumn, tableFullData, filterOpts, sortOpts, treeConfig, treeOpts, tableFullTreeData } = this
const { remote: allRemoteFilter, filterMethod: allFilterMethod } = filterOpts
const { remote: allRemoteSort, sortMethod: allSortMethod, multiple: sortMultiple, chronological } = sortOpts
const { transform } = treeOpts
let tableData = []
let tableTree = []
const filterColumns = []
let orderColumns = []
tableFullColumn.forEach(column => {
const { field, sortable, order, filters } = column
if (!allRemoteFilter && filters && filters.length) {
const valueList = []
const itemList = []
filters.forEach((item) => {
if (item.checked) {
itemList.push(item)
valueList.push(item.value)
}
})
if (itemList.length) {
filterColumns.push({ column, valueList, itemList })
}
}
if (!allRemoteSort && sortable && order) {
orderColumns.push({ column, field, property: field, order, sortTime: column.sortTime })
}
})
if (sortMultiple && chronological && orderColumns.length > 1) {
orderColumns = XEUtils.orderBy(orderColumns, 'sortTime')
}
if (filterColumns.length) {
const handleFilter = (row) => {
return filterColumns.every(({ column, valueList, itemList }) => {
if (valueList.length && !allRemoteFilter) {
const { filterMethod, filterRender, field } = column
const compConf = filterRender ? VXETable.renderer.get(filterRender.name) : null
const compFilterMethod = compConf && compConf.renderFilter ? compConf.filterMethod : null
const defaultFilterMethod = compConf ? compConf.defaultFilterMethod : null
const cellValue = UtilTools.getCellValue(row, column)
if (filterMethod) {
return itemList.some((item) => filterMethod({ value: item.value, option: item, cellValue, row, column, $table: this }))
} else if (compFilterMethod) {
return itemList.some((item) => compFilterMethod({ value: item.value, option: item, cellValue, row, column, $table: this }))
} else if (allFilterMethod) {
return allFilterMethod({ options: itemList, values: valueList, cellValue, row, column })
} else if (defaultFilterMethod) {
return itemList.some((item) => defaultFilterMethod({ value: item.value, option: item, cellValue, row, column, $table: this }))
}
return valueList.indexOf(XEUtils.get(row, field)) > -1
}
return true
})
}
if (treeConfig && transform) {
// 筛选虚拟树
tableTree = XEUtils.searchTree(tableFullTreeData, handleFilter, { ...treeOpts, original: true })
tableData = tableTree
} else {
tableData = treeConfig ? tableFullTreeData.filter(handleFilter) : tableFullData.filter(handleFilter)
tableTree = tableData
}
} else {
if (treeConfig && transform) {
// 还原虚拟树
tableTree = XEUtils.searchTree(tableFullTreeData, () => true, { ...treeOpts, original: true })
tableData = tableTree
} else {
tableData = treeConfig ? tableFullTreeData.slice(0) : tableFullData.slice(0)
tableTree = tableData
}
}
const firstOrderColumn = orderColumns[0]
if (!allRemoteSort && firstOrderColumn) {
if (treeConfig && transform) {
// 虚拟树和列表一样,只能排序根级节点
if (allSortMethod) {
const sortRests = allSortMethod({ data: tableTree, sortList: orderColumns, $table: this })
tableTree = XEUtils.isArray(sortRests) ? sortRests : tableTree
} else {
tableTree = XEUtils.orderBy(tableTree, orderColumns.map(({ column, order }) => [getOrderField(this, column), order]))
}
tableData = tableTree
} else {
if (allSortMethod) {
const sortRests = allSortMethod({ data: tableData, column: firstOrderColumn.column, property: firstOrderColumn.field, field: firstOrderColumn.field, order: firstOrderColumn.order, sortList: orderColumns, $table: this })
tableData = XEUtils.isArray(sortRests) ? sortRests : tableData
} else {
// 兼容 v4
if (sortMultiple) {
tableData = XEUtils.orderBy(tableData, orderColumns.map(({ column, order }) => [getOrderField(this, column), order]))
} else {
// 兼容 v2,在 v4 中废弃, sortBy 不能为数组
let sortByConfs
if (XEUtils.isArray(firstOrderColumn.sortBy)) {
sortByConfs = firstOrderColumn.sortBy.map(item => [item, firstOrderColumn.order])
}
tableData = XEUtils.orderBy(tableData, sortByConfs || [firstOrderColumn].map(({ column, order }) => [getOrderField(this, column), order]))
}
}
tableTree = tableData
}
}
this.afterFullData = tableData
this.afterTreeFullData = tableTree
this.updateAfterDataIndex()
},
/**
* 预编译
* 对渲染中的数据提前解析序号及索引。牺牲提前编译耗时换取渲染中额外损耗,使运行时更加流畅
*/
updateAfterDataIndex () {
const { treeConfig, afterFullData, fullDataRowIdData, fullAllDataRowIdData, afterTreeFullData, treeOpts } = this
if (treeConfig) {
XEUtils.eachTree(afterTreeFullData, (row, index, items, path) => {
const rowid = getRowid(this, row)
const allrest = fullAllDataRowIdData[rowid]
const seq = path.map((num, i) => i % 2 === 0 ? (Number(num) + 1) : '.').join('')
if (allrest) {
allrest.seq = seq
allrest._index = index
} else {
const rest = { row, rowid, seq, index: -1, $index: -1, _index: index, items: [], parent: null, level: 0 }
fullAllDataRowIdData[rowid] = rest
fullDataRowIdData[rowid] = rest
}
}, { children: treeOpts.transform ? treeOpts.mapChildren : treeOpts.children })
} else {
afterFullData.forEach((row, index) => {
const rowid = getRowid(this, row)
const allrest = fullAllDataRowIdData[rowid]
const seq = index + 1
if (allrest) {
allrest.seq = seq
allrest._index = index
} else {
const rest = { row, rowid, seq, index: -1, $index: -1, _index: index, items: [], parent: null, level: 0 }
fullAllDataRowIdData[rowid] = rest
fullDataRowIdData[rowid] = rest
}
})
}
},
/**
* 只对 tree-config 有效,获取行的父级
*/
getParentRow (rowOrRowid) {
const { treeConfig, fullDataRowIdData } = this
if (rowOrRowid && treeConfig) {
let rowid
if (XEUtils.isString(rowOrRowid)) {
rowid = rowOrRowid
} else {
rowid = getRowid(this, rowOrRowid)
}
if (rowid) {
return fullDataRowIdData[rowid] ? fullDataRowIdData[rowid].parent : null
}
}
return null
},
/**
* 根据行的唯一主键获取行
* @param {String/Number} rowid 行主键
*/
getRowById (cellValue) {
const fullDataRowIdData = this.fullDataRowIdData
const rowid = XEUtils.eqNull(cellValue) ? '' : encodeURIComponent(cellValue)
return fullDataRowIdData[rowid] ? fullDataRowIdData[rowid].row : null
},
/**
* 根据行获取行的唯一主键
* @param {Row} row 行对象
*/
getRowid (row) {
const fullAllDataRowMap = this.fullAllDataRowMap
return fullAllDataRowMap.has(row) ? fullAllDataRowMap.get(row).rowid : null
},
/**
* 获取处理后的表格数据
* 如果存在筛选条件,继续处理
* 如果存在排序,继续处理
*/
getTableData () {
const { tableFullData, afterFullData, tableData, footerTableData } = this
return {
fullData: tableFullData.slice(0),
visibleData: afterFullData.slice(0),
tableData: tableData.slice(0),
footerData: footerTableData.slice(0)
}
},
/**
* 处理数据加载默认行为
* 默认执行一次,除非被重置
*/
handleLoadDefaults () {
if (this.checkboxConfig) {
this.handleDefaultSelectionChecked()
}
if (this.radioConfig) {
this.handleDefaultRadioChecked()
}
if (this.expandConfig) {
this.handleDefaultRowExpand()
}
if (this.treeConfig) {
this.handleDefaultTreeExpand()
}
if (this.mergeCells) {
this.handleDefaultMergeCells()
}
if (this.mergeFooterItems) {
this.handleDefaultMergeFooterItems()
}
this.$nextTick(() => setTimeout(this.recalculate))
},
/**
* 处理初始化的默认行为
* 只会执行一次
*/
handleInitDefaults () {
const { sortConfig } = this
if (sortConfig) {
this.handleDefaultSort()
}
},
/**
* 设置为固定列
*/
setColumnFixed (fieldOrColumn, fixed) {
const column = handleFieldOrColumn(this, fieldOrColumn)
if (column && column.fixed !== fixed) {
XEUtils.eachTree([column], (column) => {
column.fixed = fixed
})
this.saveCustomFixed()
return this.refreshColumn()
}
return this.$nextTick()
},
/**
* 取消指定固定列
*/
clearColumnFixed (fieldOrColumn) {
const column = handleFieldOrColumn(this, fieldOrColumn)
if (column && column.fixed) {
XEUtils.eachTree([column], (column) => {
column.fixed = null
})
this.saveCustomFixed()
return this.refreshColumn()
}
return this.$nextTick()
},
/**
* 隐藏指定列
*/
hideColumn (fieldOrColumn) {
const column = handleFieldOrColumn(this, fieldOrColumn)
if (column && column.visible) {
column.visible = false
return this.handleCustom()
}
return this.$nextTick()
},
/**
* 显示指定列
*/
showColumn (fieldOrColumn) {
const column = handleFieldOrColumn(this, fieldOrColumn)
if (column & !column.visible) {
column.visible = true
return this.handleCustom()
}
return this.$nextTick()
},
setColumnWidth (fieldOrColumn, width) {
const column = handleFieldOrColumn(this, fieldOrColumn)
if (column) {
const colWidth = XEUtils.toInteger(width)
let rdWidth = colWidth
if (DomTools.isScale(width)) {
const { tableBody } = this.$refs
const tableBodyElem = tableBody ? tableBody.$el : null
const bodyWidth = tableBodyElem ? tableBodyElem.clientWidth - 1 : 0
rdWidth = Math.floor(colWidth * bodyWidth)
}
column.renderWidth = rdWidth
}
return this.$nextTick()
},
getColumnWidth (fieldOrColumn) {
const column = handleFieldOrColumn(this, fieldOrColumn)
if (column) {
return column.renderWidth
}
return 0
},
/**
* 手动重置列的显示隐藏、列宽拖动的状态;
* 如果为 true 则重置所有状态
* 如果已关联工具栏,则会同步更新
*/
resetColumn (options) {
const { customOpts } = this
const { checkMethod } = customOpts
const opts = Object.assign({ visible: true, resizable: options === true }, options)
this.tableFullColumn.forEach(column => {
if (opts.resizable) {
column.resizeWidth = 0
}
if (!checkMethod || checkMethod({ column })) {
column.visible = column.defaultVisible
}
})
if (opts.resizable) {
this.saveCustomResizable(true)
}
return this.handleCustom()
},
handleCustom () {
this.saveCustomVisible()
this.analyColumnWidth()
return this.refreshColumn()
},
/**
* 还原自定义列操作状态
*/
restoreCustomStorage () {
const { id, collectColumn, customConfig, customOpts } = this
const { storage } = customOpts
const isAllStorage = customOpts.storage === true
const isCustomResizable = isAllStorage || (storage && storage.resizable)
const isCustomVisible = isAllStorage || (storage && storage.visible)
const isCustomFixed = storage === true || (storage && storage.fixed)
const isCustomOrder = storage === true || (storage && storage.order)
if (customConfig && (isCustomResizable || isCustomVisible || isCustomFixed || isCustomOrder)) {
const customMap = {}
if (!id) {
errLog('vxe.error.reqProp', ['id'])
return
}
if (isCustomResizable) {
const columnWidthStorage = getCustomStorageMap(resizableStorageKey)[id]
if (columnWidthStorage) {
XEUtils.each(columnWidthStorage, (resizeWidth, field) => {
customMap[field] = { field, resizeWidth }
})
}
}
// 自定义固定列
if (isCustomFixed) {
const columnFixedStorage = getCustomStorageMap(fixedStorageKey)[id]
if (columnFixedStorage) {
const colFixeds = columnFixedStorage.split(',')
colFixeds.forEach((fixConf) => {
const [field, fixed] = fixConf.split('|')
if (customMap[field]) {
customMap[field].fixed = fixed
} else {
customMap[field] = { field, fixed }
}
})
}
}
// 自定义顺序
if (isCustomOrder) {
const columnOrderStorage = getCustomStorageMap(orderStorageKey)[id]
if (columnOrderStorage) {
// 开发中...
}
}
if (isCustomVisible) {
const columnVisibleS