From f3b65aee7af4d50bdc35321f29358e403434f916 Mon Sep 17 00:00:00 2001 From: xuliangzhan Date: Fri, 12 Jul 2024 18:30:44 +0800 Subject: [PATCH] releases 4.7.49 --- examples/App.vue | 1 + examples/router/index.ts | 5 ++ examples/views/table/TableTest5.vue | 59 +++++++++++++++++++ package.json | 4 +- packages/grid/src/grid.ts | 6 +- packages/table/src/cell.ts | 19 +++--- packages/table/src/columnInfo.ts | 1 + packages/table/src/table.ts | 91 +++++++++++++++++++++++------ styles/components/table.scss | 20 +++++-- 9 files changed, 169 insertions(+), 37 deletions(-) create mode 100644 examples/views/table/TableTest5.vue diff --git a/examples/App.vue b/examples/App.vue index 4e47a5c42f..e839e99671 100644 --- a/examples/App.vue +++ b/examples/App.vue @@ -27,6 +27,7 @@ const navList = ref([ { name: 'TableTest2', routerLink: { name: 'TableTest2' } }, { name: 'TableTest3', routerLink: { name: 'TableTest3' } }, { name: 'TableTest4', routerLink: { name: 'TableTest4' } }, + { name: 'TableTest5', routerLink: { name: 'TableTest5' } }, { name: 'GridTest', routerLink: { name: 'GridTest' } }, { name: 'TestKeepTest1', routerLink: { name: 'TestKeepTest1' } }, { name: 'TestKeepTest2', routerLink: { name: 'TestKeepTest2' } }, diff --git a/examples/router/index.ts b/examples/router/index.ts index 916d76316d..ae2b61767d 100644 --- a/examples/router/index.ts +++ b/examples/router/index.ts @@ -45,6 +45,11 @@ const routes: Array = [ name: 'TableTest4', component: () => import('../views/table/TableTest4.vue') }, + { + path: '/component/table5', + name: 'TableTest5', + component: () => import('../views/table/TableTest5.vue') + }, { path: '/component/grid', name: 'GridTest', diff --git a/examples/views/table/TableTest5.vue b/examples/views/table/TableTest5.vue new file mode 100644 index 0000000000..0e8763287e --- /dev/null +++ b/examples/views/table/TableTest5.vue @@ -0,0 +1,59 @@ + + + diff --git a/package.json b/package.json index 10ccc73af5..ae9bdf878a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vxe-table", - "version": "4.7.48", + "version": "4.7.49", "description": "一个基于 vue 的 PC 端表格组件,支持增删改查、虚拟树、列拖拽,懒加载、快捷菜单、数据校验、树形结构、打印、导入导出、自定义模板、渲染器、JSON 配置式...", "scripts": { "update": "npm install --legacy-peer-deps", @@ -28,7 +28,7 @@ "style": "lib/style.css", "typings": "types/index.d.ts", "dependencies": { - "vxe-pc-ui": "^4.0.61" + "vxe-pc-ui": "^4.0.63" }, "devDependencies": { "@types/resize-observer-browser": "^0.1.11", diff --git a/packages/grid/src/grid.ts b/packages/grid/src/grid.ts index bbf079af2b..96e7eb42bf 100644 --- a/packages/grid/src/grid.ts +++ b/packages/grid/src/grid.ts @@ -184,9 +184,9 @@ export default defineComponent({ const tableProps = Object.assign({}, tableExtendProps) if (isZMax) { if (tableExtendProps.maxHeight) { - tableProps.maxHeight = 'auto' + tableProps.maxHeight = 'fill' } else { - tableProps.height = 'auto' + tableProps.height = 'fill' } } if (proxyConfig && isEnableConf(proxyOpts)) { @@ -1125,7 +1125,7 @@ export default defineComponent({ const topWrapper = refTopWrapper.value const bottomWrapper = refBottomWrapper.value const pagerWrapper = refPagerWrapper.value - const parentPaddingSize = isZMax || height !== 'auto' ? 0 : getPaddingTopBottomSize(el.parentNode as HTMLElement) + const parentPaddingSize = isZMax || !(height === 'auto' || height === 'fill') ? 0 : getPaddingTopBottomSize(el.parentNode as HTMLElement) return parentPaddingSize + getPaddingTopBottomSize(el) + getOffsetHeight(formWrapper) + getOffsetHeight(toolbarWrapper) + getOffsetHeight(topWrapper) + getOffsetHeight(bottomWrapper) + getOffsetHeight(pagerWrapper) }, getParentHeight () { diff --git a/packages/table/src/cell.ts b/packages/table/src/cell.ts index 1eafde1863..afff3f91eb 100644 --- a/packages/table/src/cell.ts +++ b/packages/table/src/cell.ts @@ -252,9 +252,10 @@ export const Cell = { */ renderTreeIcon (params: VxeTableDefines.CellRenderBodyParams, cellVNodes: VxeComponentSlotType[]) { const { $table, isHidden } = params - const { reactData } = $table + const { reactData, internalData } = $table const { computeTreeOpts } = $table.getComputeMaps() const { treeExpandedMaps, treeExpandLazyLoadedMaps } = reactData + const { fullAllDataRowIdData } = internalData const treeOpts = computeTreeOpts.value const { row, column, level } = params const { slots } = column @@ -262,9 +263,11 @@ export const Cell = { const childrenField = treeOpts.children || treeOpts.childrenField const hasChildField = treeOpts.hasChild || treeOpts.hasChildField const rowChilds = row[childrenField] + const hasChild = rowChilds && rowChilds.length const iconSlot = slots ? slots.icon : null let hasLazyChilds = false let isAceived = false + let isLazyLoading = false let isLazyLoaded = false const ons: any = {} if (iconSlot) { @@ -274,8 +277,10 @@ export const Cell = { const rowid = getRowid($table, row) isAceived = !!treeExpandedMaps[rowid] if (lazy) { - isLazyLoaded = !!treeExpandLazyLoadedMaps[rowid] + const rest = fullAllDataRowIdData[rowid] + isLazyLoading = !!treeExpandLazyLoadedMaps[rowid] hasLazyChilds = row[hasChildField] + isLazyLoaded = !!rest.treeLoaded } } if (!trigger || trigger === 'default') { @@ -292,14 +297,14 @@ export const Cell = { paddingLeft: `${level * indent}px` } }, [ - showIcon && ((rowChilds && rowChilds.length) || hasLazyChilds) + showIcon && (lazy ? (isLazyLoaded ? hasChild : hasLazyChilds) : hasChild) ? [ h('div', { class: 'vxe-tree--btn-wrapper', ...ons }, [ h('i', { - class: ['vxe-tree--node-btn', isLazyLoaded ? (iconLoaded || getIcon().TABLE_TREE_LOADED) : (isAceived ? (iconOpen || getIcon().TABLE_TREE_OPEN) : (iconClose || getIcon().TABLE_TREE_CLOSE))] + class: ['vxe-tree--node-btn', isLazyLoading ? (iconLoaded || getIcon().TABLE_TREE_LOADED) : (isAceived ? (iconOpen || getIcon().TABLE_TREE_OPEN) : (iconClose || getIcon().TABLE_TREE_CLOSE))] }) ]) ] @@ -622,7 +627,7 @@ export const Cell = { const defaultSlot = slots ? slots.default : null const iconSlot = slots ? slots.icon : null let isAceived = false - let isLazyLoaded = false + let isLazyLoading = false if (iconSlot) { return $table.callSlot(iconSlot, params) } @@ -630,7 +635,7 @@ export const Cell = { const rowid = getRowid($table, row) isAceived = !!rowExpandedMaps[rowid] if (lazy) { - isLazyLoaded = !!rowExpandLazyLoadedMaps[rowid] + isLazyLoading = !!rowExpandLazyLoadedMaps[rowid] } } return [ @@ -644,7 +649,7 @@ export const Cell = { } }, [ h('i', { - class: ['vxe-table--expand-btn', isLazyLoaded ? (iconLoaded || getIcon().TABLE_EXPAND_LOADED) : (isAceived ? (iconOpen || getIcon().TABLE_EXPAND_OPEN) : (iconClose || getIcon().TABLE_EXPAND_CLOSE))] + class: ['vxe-table--expand-btn', isLazyLoading ? (iconLoaded || getIcon().TABLE_EXPAND_LOADED) : (isAceived ? (iconOpen || getIcon().TABLE_EXPAND_OPEN) : (iconClose || getIcon().TABLE_EXPAND_CLOSE))] }) ]) : null, diff --git a/packages/table/src/columnInfo.ts b/packages/table/src/columnInfo.ts index ba9c5fa2bb..a9990ecd9b 100644 --- a/packages/table/src/columnInfo.ts +++ b/packages/table/src/columnInfo.ts @@ -128,6 +128,7 @@ export class ColumnInfo { renderWidth: 0, renderHeight: 0, renderResizeWidth: 0, + renderAutoWidth: 0, resizeWidth: 0, // 手动调整 renderLeft: 0, diff --git a/packages/table/src/table.ts b/packages/table/src/table.ts index bfb12d288d..26ed7c6930 100644 --- a/packages/table/src/table.ts +++ b/packages/table/src/table.ts @@ -43,6 +43,7 @@ export default defineComponent({ const { computeSize } = useFns.useSize(props) const reactData = reactive({ + isCalcColumn: false, // 低性能的静态列 staticColumns: [], // 渲染的列分组 @@ -155,7 +156,8 @@ export default defineComponent({ pxMinList: [], scaleList: [], scaleMinList: [], - autoList: [] + autoList: [], + remainList: [] }, // 存放快捷菜单的信息 ctxMenuStore: { @@ -537,6 +539,11 @@ export default defineComponent({ return Object.assign({}, getConfig().table.customConfig, props.customConfig) }) + const computeAutoWidthColumnList = computed(() => { + const { visibleColumn } = internalData + return visibleColumn.filter(column => column.width === 'auto') + }) + const computeFixedColumnSize = computed(() => { const { collectColumn } = internalData let fixedSize = 0 @@ -883,7 +890,7 @@ export default defineComponent({ const val = props[key] let num = 0 if (val) { - if (val === 'auto') { + if (val === 'fill' || val === 'auto') { num = parentHeight } else { const excludeHeight = $xeTable.getExcludeHeight() @@ -1084,6 +1091,40 @@ export default defineComponent({ internalData.customMaxHeight = calcHeight('maxHeight') } + const calcCellWidth = () => { + const { tableData } = reactData + const autoWidthColumnList = computeAutoWidthColumnList.value + if (!tableData.length || !autoWidthColumnList.length) { + reactData.isCalcColumn = false + return nextTick() + } + reactData.isCalcColumn = true + return nextTick().then(() => { + const el = refElem.value + if (el) { + autoWidthColumnList.forEach(column => { + const cellElList = el.querySelectorAll(`.vxe-body--column.${column.id}>.vxe-cell`) + const firstCellEl = cellElList[0] + let paddingSize = 0 + if (firstCellEl) { + const cellStyle = getComputedStyle(firstCellEl) + paddingSize = Math.floor(XEUtils.toNumber(cellStyle.paddingLeft) + XEUtils.toNumber(cellStyle.paddingRight)) + 2 + } + let colWidth = column.renderAutoWidth - paddingSize + 2 + XEUtils.arrayEach(cellElList, (cellEl) => { + const labelEl = cellEl.firstChild as HTMLElement + if (labelEl) { + colWidth = Math.max(colWidth, labelEl.offsetWidth) + } + }) + column.renderAutoWidth = colWidth + paddingSize + }) + tablePrivateMethods.analyColumnWidth() + } + reactData.isCalcColumn = false + }) + } + /** * 列宽算法 * 支持 px、%、固定 混合分配 @@ -1107,7 +1148,7 @@ export default defineComponent({ let meanWidth = remainWidth / 100 const { fit } = props const { columnStore } = reactData - const { resizeList, pxMinList, pxList, scaleList, scaleMinList, autoList } = columnStore + const { resizeList, pxMinList, pxList, scaleList, scaleMinList, autoList, remainList } = columnStore // 最小宽 pxMinList.forEach((column) => { const minWidth = XEUtils.toInteger(column.minWidth) @@ -1132,6 +1173,12 @@ export default defineComponent({ tableWidth += width column.renderWidth = width }) + // 自适应宽 + autoList.forEach((column) => { + const width = Math.max(60, XEUtils.toInteger(column.renderAutoWidth)) + tableWidth += width + column.renderWidth = width + }) // 调整了列宽 resizeList.forEach((column) => { const width = XEUtils.toInteger(column.resizeWidth) @@ -1139,7 +1186,7 @@ export default defineComponent({ column.renderWidth = width }) remainWidth -= tableWidth - meanWidth = remainWidth > 0 ? Math.floor(remainWidth / (scaleMinList.length + pxMinList.length + autoList.length)) : 0 + meanWidth = remainWidth > 0 ? Math.floor(remainWidth / (scaleMinList.length + pxMinList.length + remainList.length)) : 0 if (fit) { if (remainWidth > 0) { scaleMinList.concat(pxMinList).forEach((column) => { @@ -1150,8 +1197,8 @@ export default defineComponent({ } else { meanWidth = minCellWidth } - // 自适应 - autoList.forEach((column) => { + // 剩余均分 + remainList.forEach((column) => { const width = Math.max(meanWidth, minCellWidth) column.renderWidth = width tableWidth += width @@ -1161,7 +1208,7 @@ export default defineComponent({ * 偏移量算法 * 如果所有列足够放的情况下,从最后动态列开始分配 */ - const dynamicList = scaleList.concat(scaleMinList).concat(pxMinList).concat(autoList) + const dynamicList = scaleList.concat(scaleMinList).concat(pxMinList).concat(remainList) let dynamicSize = dynamicList.length - 1 if (dynamicSize > 0) { let odiffer = bodyWidth - tableWidth @@ -2053,7 +2100,9 @@ export default defineComponent({ const rowid = getRowid($xeTable, row) const rest = fullAllDataRowIdData[rowid] treeExpandLazyLoadedMaps[rowid] = row - loadMethod({ $table: $xeTable, row }).then((childRecords: any) => { + Promise.resolve( + loadMethod({ $table: $xeTable, row }) + ).then((childRecords: any) => { rest.treeLoaded = true if (treeExpandLazyLoadedMaps[rowid]) { delete treeExpandLazyLoadedMaps[rowid] @@ -3486,6 +3535,7 @@ export default defineComponent({ * 支持 width=? width=?px width=?% min-width=? min-width=?px min-width=?% */ recalculate (refull?: boolean) { + calcCellWidth() autoCellWidth() if (refull === true) { // 初始化时需要在列计算之后再执行优化运算,达到最优显示效果 @@ -5203,7 +5253,6 @@ export default defineComponent({ /** * 处理显示 tooltip * @param {Event} evnt 事件 - * @param {ColumnInfo} column 列配置 * @param {Row} row 行对象 */ const handleTooltip = (evnt: MouseEvent, cell: HTMLTableCellElement, overflowElem: HTMLElement, tipElem: HTMLElement | null, params: any) => { @@ -5271,7 +5320,7 @@ export default defineComponent({ const el = refElem.value if (el) { const parentElem = el.parentNode as HTMLElement - const parentPaddingSize = height === 'auto' ? getPaddingTopBottomSize(parentElem) : 0 + const parentPaddingSize = height === 'fill' || height === 'auto' ? getPaddingTopBottomSize(parentElem) : 0 return Math.floor($xeGrid ? $xeGrid.getParentHeight() : XEUtils.toNumber(getComputedStyle(parentElem).height) - parentPaddingSize) } return 0 @@ -5423,12 +5472,13 @@ export default defineComponent({ const { tableFullColumn } = internalData const columnOpts = computeColumnOpts.value const { width: defaultWidth, minWidth: defaultMinWidth } = columnOpts - const resizeList: any[] = [] - const pxList: any[] = [] - const pxMinList: any[] = [] - const scaleList: any[] = [] - const scaleMinList: any[] = [] - const autoList: any[] = [] + const resizeList: VxeTableDefines.ColumnInfo[] = [] + const pxList: VxeTableDefines.ColumnInfo[] = [] + const pxMinList: VxeTableDefines.ColumnInfo[] = [] + const scaleList: VxeTableDefines.ColumnInfo[] = [] + const scaleMinList: VxeTableDefines.ColumnInfo[] = [] + const autoList: VxeTableDefines.ColumnInfo[] = [] + const remainList: VxeTableDefines.ColumnInfo[] = [] tableFullColumn.forEach((column) => { if (defaultWidth && !column.width) { column.width = defaultWidth @@ -5439,6 +5489,8 @@ export default defineComponent({ if (column.visible) { if (column.resizeWidth) { resizeList.push(column) + } else if (column.width === 'auto') { + autoList.push(column) } else if (isPx(column.width)) { pxList.push(column) } else if (isScale(column.width)) { @@ -5448,11 +5500,11 @@ export default defineComponent({ } else if (isScale(column.minWidth)) { scaleMinList.push(column) } else { - autoList.push(column) + remainList.push(column) } } }) - Object.assign(reactData.columnStore, { resizeList, pxList, pxMinList, scaleList, scaleMinList, autoList }) + Object.assign(reactData.columnStore, { resizeList, pxList, pxMinList, scaleList, scaleMinList, autoList, remainList }) }, saveCustomStore (type) { const { id } = props @@ -6853,7 +6905,7 @@ export default defineComponent({ const renderVN = () => { const { loading, stripe, showHeader, height, treeConfig, mouseConfig, showFooter, highlightCell, highlightHoverRow, highlightHoverColumn, editConfig, editRules } = props - const { isGroup, overflowX, overflowY, scrollXLoad, scrollYLoad, scrollbarHeight, tableData, tableColumn, tableGroupColumn, footerTableData, initStore, columnStore, filterStore, customStore, tooltipStore } = 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 @@ -6882,6 +6934,7 @@ export default defineComponent({ 'row--highlight': rowOpts.isHover || highlightHoverRow, 'column--highlight': columnOpts.isHover || highlightHoverColumn, 'checkbox--range': checkboxOpts.range, + 'column--calc': isCalcColumn, 'is--header': showHeader, 'is--footer': showFooter, 'is--group': isGroup, diff --git a/styles/components/table.scss b/styles/components/table.scss index 625bf2cc58..5e473b5e4b 100644 --- a/styles/components/table.scss +++ b/styles/components/table.scss @@ -315,6 +315,19 @@ } } +/*列宽*/ +.vxe-table { + &.column--calc { + .vxe-header--column, + .vxe-body--column { + .vxe-cell { + word-break: break-all; + white-space: nowrap; + } + } + } +} + /*header*/ .vxe-table { .vxe-table--header-wrapper { @@ -620,11 +633,6 @@ } } } - &.checkbox--range { - .vxe-body--column { - user-select: none; - } - } &.cell--area { .vxe-table--body-wrapper, .vxe-body--column { @@ -632,7 +640,7 @@ } } &.drag--range { - .vxe-cell--checkbox { + .vxe-body--column { user-select: none; } }