stk-table-vue 0.8.3 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stk-table-vue",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "Simple realtime virtual table for vue3 and vue2.7",
5
5
  "main": "./lib/stk-table-vue.js",
6
6
  "types": "./lib/src/StkTable/index.d.ts",
@@ -63,9 +63,9 @@
63
63
  "typescript": "^5.8.3",
64
64
  "vite": "^7.0.2",
65
65
  "vite-plugin-dts": "3.9.1",
66
- "vitepress": "^1.6.3",
66
+ "vitepress": "^1.6.4",
67
67
  "vitepress-demo-plugin": "^1.4.5",
68
- "vitepress-plugin-llms": "^1.7.0",
68
+ "vitepress-plugin-llms": "^1.7.5",
69
69
  "vitest": "^3.2.4",
70
70
  "vue": "^3.5.17",
71
71
  "vue-eslint-parser": "^9.4.2"
@@ -36,15 +36,14 @@
36
36
  @scroll="onTableScroll"
37
37
  @wheel="onTableWheel"
38
38
  >
39
- <!-- 这个元素用于整数行虚拟滚动时,撑开父容器的高度) -->
39
+
40
40
  <div
41
41
  v-if="isSRBRActive && virtual"
42
42
  class="row-by-row-table-height"
43
43
  :style="{ height: dataSourceCopy.length * virtualScroll.rowHeight + 'px' }"
44
- ></div>
44
+ ><!-- 这个元素用于整数行虚拟滚动时,撑开父容器的高度) --></div>
45
45
 
46
46
  <div v-if="colResizable" ref="colResizeIndicatorRef" class="column-resize-indicator"></div>
47
- <!-- 表格主体 -->
48
47
  <table
49
48
  class="stk-table-main"
50
49
  :style="{ width, minWidth, maxWidth }"
@@ -52,15 +51,13 @@
52
51
  'fixed-mode': props.fixedMode,
53
52
  }"
54
53
  >
55
- <thead v-if="!headless" ref="theadRef">
54
+ <thead v-if="!headless">
56
55
  <tr v-for="(row, rowIndex) in tableHeaders" :key="rowIndex" @contextmenu="onHeaderMenu($event)">
57
- <!-- 这个th用于横向虚拟滚动表格左边距,width、maxWidth 用于兼容低版本浏览器 -->
58
56
  <th
59
57
  v-if="virtualX_on"
60
58
  class="vt-x-left"
61
59
  :style="`min-width:${virtualScrollX.offsetLeft}px;width:${virtualScrollX.offsetLeft}px`"
62
60
  ></th>
63
- <!-- v for中最后一行才用 切割。-->
64
61
  <th
65
62
  v-for="(col, colIndex) in virtualX_on && rowIndex === tableHeaders.length - 1 ? virtualX_columnPart : row"
66
63
  :key="colKeyGen(col)"
@@ -101,17 +98,14 @@
101
98
  </template>
102
99
  <SortIcon v-if="col.sorter" class="table-header-sorter" />
103
100
  </div>
104
- <!-- 列宽拖动handler -->
105
101
  <div v-if="colResizeOn(col)" class="table-header-resizer right" @mousedown="onThResizeMouseDown($event, col)"></div>
106
102
  </th>
107
- <!-- 这个th用于横向虚拟滚动表格右边距 width, min-width 用于兼容低版本浏览器-->
108
103
  <th v-if="virtualX_on" class="vt-x-right" :style="`min-width:${virtualX_offsetRight}px;width:${virtualX_offsetRight}px`"></th>
109
104
  </tr>
110
105
  </thead>
111
106
 
112
107
  <tbody class="stk-tbody-main" @dragover="onTrDragOver" @dragenter="onTrDragEnter" @dragend="onTrDragEnd">
113
108
  <tr v-if="virtual_on && !isSRBRActive" :style="`height:${virtualScroll.offsetTop}px`" class="padding-top-tr">
114
- <!--这个td用于配合虚拟滚动的th对应,防止列错位-->
115
109
  <td v-if="virtualX_on && fixedMode && headless" class="vt-x-left"></td>
116
110
  <template v-if="fixedMode && headless">
117
111
  <td v-for="col in virtualX_columnPart" :key="colKeyGen(col)" :style="cellStyleMap[TagType.TD].get(colKeyGen(col))"></td>
@@ -141,10 +135,8 @@
141
135
  @mouseleave="onTrMouseLeave($event)"
142
136
  @drop="onTrDrop($event, getRowIndex(rowIndex))"
143
137
  >
144
- <!--这个td用于配合虚拟滚动的th对应,防止列错位-->
145
138
  <td v-if="virtualX_on" class="vt-x-left"></td>
146
139
  <td v-if="row && row.__EXPANDED_ROW__" :colspan="virtualX_columnPart.length">
147
- <!-- TODO: support wheel -->
148
140
  <div class="table-cell-wrapper">
149
141
  <slot name="expand" :row="row.__EXPANDED_ROW__" :col="row.__EXPANDED_COL__">
150
142
  {{ row.__EXPANDED_ROW__?.[row.__EXPANDED_COL__.dataIndex] ?? '' }}
@@ -293,13 +285,14 @@ import { useFixedStyle } from './useFixedStyle';
293
285
  import { useGetFixedColPosition } from './useGetFixedColPosition';
294
286
  import { useHighlight } from './useHighlight';
295
287
  import { useKeyboardArrowScroll } from './useKeyboardArrowScroll';
288
+ import { useMaxRowSpan } from './useMaxRowSpan';
289
+ import { useMergeCells } from './useMergeCells';
296
290
  import { useRowExpand } from './useRowExpand';
297
291
  import { useScrollRowByRow } from './useScrollRowByRow';
298
292
  import { useThDrag } from './useThDrag';
299
293
  import { useTrDrag } from './useTrDrag';
300
294
  import { useTree } from './useTree';
301
295
  import { useVirtualScroll } from './useVirtualScroll';
302
- import { useMergeCells } from './useMergeCells';
303
296
  import { createStkTableId, getCalculatedColWidth, getColWidth } from './utils/constRefUtils';
304
297
  import { howDeepTheHeader, isEmptyValue, tableSort, transformWidthToStr } from './utils/index';
305
298
 
@@ -649,7 +642,6 @@ const emits = defineEmits<{
649
642
  // }>();
650
643
 
651
644
  const tableContainerRef = ref<HTMLDivElement>();
652
- const theadRef = ref<HTMLElement>();
653
645
  const colResizeIndicatorRef = ref<HTMLDivElement>();
654
646
  const trRef = ref<HTMLTableRowElement[]>();
655
647
 
@@ -687,7 +679,7 @@ const sortSwitchOrder: Order[] = [null, 'desc', 'asc'];
687
679
  * @eg
688
680
  * ```js
689
681
  * [
690
- * [{dataInex:'id',...}], // 第0行列配置
682
+ * [{dataIndex:'id',...}], // 第0行列配置
691
683
  * [], // 第一行列配置
692
684
  * //...
693
685
  * ]
@@ -761,6 +753,8 @@ const { onThDragStart, onThDragOver, onThDrop, isHeaderDraggable } = useThDrag({
761
753
 
762
754
  const { onTrDragStart, onTrDrop, onTrDragOver, onTrDragEnd, onTrDragEnter } = useTrDrag({ props, emits, dataSourceCopy });
763
755
 
756
+ const { maxRowSpan, updateMaxRowSpan } = useMaxRowSpan({ props, tableHeaderLast, rowKeyGen, dataSourceCopy });
757
+
764
758
  const {
765
759
  virtualScroll,
766
760
  virtualScrollX,
@@ -777,7 +771,16 @@ const {
777
771
  updateVirtualScrollX,
778
772
  setAutoHeight,
779
773
  clearAllAutoHeight,
780
- } = useVirtualScroll({ tableContainerRef, trRef, props, dataSourceCopy, tableHeaderLast, tableHeaders, rowKeyGen });
774
+ } = useVirtualScroll({ tableContainerRef, trRef, props, dataSourceCopy, tableHeaderLast, tableHeaders, rowKeyGen, maxRowSpan });
775
+
776
+ const {
777
+ hiddenCellMap, //
778
+ mergeCellsWrapper,
779
+ hoverMergedCells,
780
+ updateHoverMergedCells,
781
+ activeMergedCells,
782
+ updateActiveMergedCells,
783
+ } = useMergeCells({ props, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart });
781
784
 
782
785
  const getFixedColPosition = useGetFixedColPosition({ colKeyGen, tableHeadersForCalc });
783
786
 
@@ -831,19 +834,12 @@ const { toggleExpandRow, setRowExpand } = useRowExpand({ dataSourceCopy, rowKeyG
831
834
 
832
835
  const { toggleTreeNode, setTreeExpand, flatTreeData } = useTree({ props, dataSourceCopy, rowKeyGen, emits });
833
836
 
834
- const { hiddenCellMap, mergeCellsWrapper, hoverMergedCells, updateHoverMergedCells, activeMergedCells, updateActiveMergedCells } = useMergeCells({
835
- props,
836
- tableHeaderLast,
837
- rowKeyGen,
838
- colKeyGen,
839
- virtual_dataSourcePart,
840
- });
841
-
842
837
  watch(
843
838
  () => props.columns,
844
839
  () => {
845
840
  dealColumns();
846
- // initVirtualScrollX 需要获取容器滚动宽度等。必须等渲染完成后再调用。因此使用nextTick。
841
+ updateMaxRowSpan();
842
+ // nextTick: initVirtualScrollX need get container width。
847
843
  nextTick(() => {
848
844
  initVirtualScrollX();
849
845
  updateFixedShadow();
@@ -885,12 +881,13 @@ watch(
885
881
  console.warn('invalid dataSource');
886
882
  return;
887
883
  }
888
- /** 是否需要更新ScrollY,这里由于watch newValue与oldValue 的长度一样,因此需要这样使用 */
884
+
889
885
  let needInitVirtualScrollY = false;
890
886
  if (dataSourceCopy.value.length !== val.length) {
891
887
  needInitVirtualScrollY = true;
892
888
  }
893
889
  initDataSource(val);
890
+ updateMaxRowSpan();
894
891
  // if data length is not change, not init virtual scroll
895
892
  if (needInitVirtualScrollY) {
896
893
  // wait for table render,initVirtualScrollY has get `dom` operation.
@@ -913,6 +910,7 @@ watch(
913
910
 
914
911
  dealColumns();
915
912
  initDataSource();
913
+ updateMaxRowSpan();
916
914
 
917
915
  onMounted(() => {
918
916
  initVirtualScroll();
@@ -1327,7 +1325,7 @@ function onTableScroll(e: Event) {
1327
1325
  if (!e?.target) return;
1328
1326
 
1329
1327
  const { scrollTop, scrollLeft } = e.target as HTMLElement;
1330
- const { scrollTop: vScrollTop, startIndex, endIndex } = virtualScroll.value;
1328
+ const { scrollTop: vScrollTop } = virtualScroll.value;
1331
1329
  const { scrollLeft: vScrollLeft } = virtualScrollX.value;
1332
1330
  const isYScroll = scrollTop !== vScrollTop;
1333
1331
  const isXScroll = scrollLeft !== vScrollLeft;
@@ -1349,6 +1347,7 @@ function onTableScroll(e: Event) {
1349
1347
  }
1350
1348
 
1351
1349
  if (isYScroll) {
1350
+ const { startIndex, endIndex } = virtualScroll.value;
1352
1351
  emits('scroll', e, { startIndex, endIndex });
1353
1352
  }
1354
1353
  if (isXScroll) {
@@ -381,7 +381,8 @@
381
381
  }
382
382
 
383
383
  .highlight-cell {
384
- animation: stk-table-dim var(--highlight-duration);
384
+ animation-name: stk-table-dim;
385
+ animation-duration: var(--highlight-duration);
385
386
  animation-timing-function: var(--highlight-timing-function);
386
387
  /* 必须分开写,否则var(step(x))不兼容旧浏览器*/
387
388
  }
@@ -504,7 +505,8 @@
504
505
 
505
506
  /* td inherit tr bgc*/
506
507
  .highlight-row {
507
- animation: stk-table-dim var(--highlight-duration);
508
+ animation-name: stk-table-dim;
509
+ animation-duration: var(--highlight-duration);
508
510
  /* 必须分开写,否则var(step(x))不兼容旧浏览器*/
509
511
  animation-timing-function: var(--highlight-timing-function);
510
512
  }
@@ -0,0 +1,56 @@
1
+ import { ShallowRef } from "vue";
2
+ import { PrivateStkTableColumn, RowKeyGen, UniqKey } from "./types";
3
+
4
+ type Options = {
5
+ props:any,
6
+ tableHeaderLast: ShallowRef<PrivateStkTableColumn<any>[]>;
7
+ rowKeyGen: RowKeyGen;
8
+ dataSourceCopy: ShallowRef<any[]>;
9
+ }
10
+
11
+ export function useMaxRowSpan({ props, tableHeaderLast, rowKeyGen, dataSourceCopy }: Options) {
12
+ /** max rowspan of each row */
13
+ const maxRowSpan = new Map<UniqKey, number>();
14
+
15
+ /**
16
+ * Use dataSourceCopy and tableHeaderLast to calculate maxRowSpan
17
+ * @link {maxRowSpan}
18
+ */
19
+ function updateMaxRowSpan() {
20
+ if(!props.virtual) {
21
+ if(maxRowSpan.size) maxRowSpan.clear();
22
+ return;
23
+ }
24
+ maxRowSpan.clear();
25
+
26
+ const data = dataSourceCopy.value;
27
+ const columns = tableHeaderLast.value;
28
+
29
+ const columnsWithMerge = columns.filter(col => col.mergeCells);
30
+ if (!columnsWithMerge.length) return;
31
+
32
+ const dataLength = data.length;
33
+ const mergeColumnsLength = columnsWithMerge.length;
34
+
35
+ for (let rowIndex = 0; rowIndex < dataLength; rowIndex++) {
36
+ const row = data[rowIndex];
37
+ const rowKey = rowKeyGen(row);
38
+ let currentMax = maxRowSpan.get(rowKey) || 0;
39
+
40
+ for (let colIndex = 0; colIndex < mergeColumnsLength; colIndex++) {
41
+ const col = columnsWithMerge[colIndex];
42
+ const { rowspan = 1 } = col.mergeCells!({ row, col, rowIndex, colIndex }) || {};
43
+
44
+ if (rowspan > 1 && rowspan > currentMax) {
45
+ currentMax = rowspan;
46
+ maxRowSpan.set(rowKey, currentMax);
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ return {
53
+ maxRowSpan,
54
+ updateMaxRowSpan
55
+ }
56
+ }
@@ -1,20 +1,20 @@
1
1
  import { ref, ShallowRef, watch } from 'vue';
2
2
  import { ColKeyGen, MergeCellsParam, PrivateStkTableColumn, RowKeyGen, UniqKey } from './types';
3
3
  import { pureCellKeyGen } from './utils';
4
-
4
+ type Options = {
5
+ props: any;
6
+ tableHeaderLast: ShallowRef<PrivateStkTableColumn<any>[]>;
7
+ rowKeyGen: RowKeyGen;
8
+ colKeyGen: ColKeyGen;
9
+ virtual_dataSourcePart: ShallowRef<any[]>;
10
+ }
5
11
  export function useMergeCells({
6
12
  props,
7
13
  tableHeaderLast,
8
14
  rowKeyGen,
9
15
  colKeyGen,
10
16
  virtual_dataSourcePart,
11
- }: {
12
- props: any;
13
- tableHeaderLast: ShallowRef<PrivateStkTableColumn<any>[]>;
14
- rowKeyGen: RowKeyGen;
15
- colKeyGen: ColKeyGen;
16
- virtual_dataSourcePart: ShallowRef<any[]>;
17
- }) {
17
+ }:Options ) {
18
18
  /**
19
19
  * which cell need be hidden
20
20
  * - key: rowKey
@@ -33,16 +33,19 @@ export function useMergeCells({
33
33
  /** click current row , which rowspan cells should be highlight */
34
34
  const activeMergedCells = ref(new Set<string>());
35
35
 
36
+
36
37
  watch([virtual_dataSourcePart, tableHeaderLast], () => {
37
38
  hiddenCellMap.value = {};
38
39
  hoverRowMap.value = {};
39
40
  });
40
41
 
41
- /** 抽象隐藏单元格的逻辑 */
42
+ /**
43
+ * abstract the logic of hiding cells
44
+ */
42
45
  function hideCells(rowKey: UniqKey, startIndex: number, count: number, isSelfRow = false, mergeCellKey: string) {
43
46
  for (let i = startIndex; i < startIndex + count; i++) {
44
47
  if (!isSelfRow || i !== startIndex) {
45
- // 自己不需要隐藏
48
+ // self row does not need to be hidden
46
49
  const nextCol = tableHeaderLast.value[i];
47
50
  if (!nextCol) break;
48
51
  const nextColKey = colKeyGen.value(nextCol);
@@ -81,20 +84,18 @@ export function useMergeCells({
81
84
  if (colspan === 1 && rowspan === 1) return;
82
85
 
83
86
  const rowKey = rowKeyGen(row);
87
+
84
88
  const colKey = colKeyGen.value(col);
85
- const dataSourceSlice = virtual_dataSourcePart.value.slice();
86
89
  const curColIndex = tableHeaderLast.value.findIndex(item => colKeyGen.value(item) === colKey);
87
- const curRowIndex = dataSourceSlice.findIndex(item => rowKeyGen(item) === rowKey);
90
+ const curRowIndex = virtual_dataSourcePart.value.findIndex(item => rowKeyGen(item) === rowKey);
88
91
  const mergedCellKey = pureCellKeyGen(rowKey, colKey);
89
92
 
90
93
  if (curRowIndex === -1) return;
91
-
94
+
92
95
  for (let i = curRowIndex; i < curRowIndex + rowspan; i++) {
93
- const row = dataSourceSlice[i];
96
+ const row = virtual_dataSourcePart.value[i];
94
97
  if (!row) break;
95
- const rKey = rowKeyGen(row);
96
- const isSelfRow = i === curRowIndex;
97
- hideCells(rKey, curColIndex, colspan, isSelfRow, mergedCellKey);
98
+ hideCells(rowKeyGen(row), curColIndex, colspan, i === curRowIndex, mergedCellKey);
98
99
  }
99
100
 
100
101
  return { colspan, rowspan };
@@ -11,6 +11,7 @@ type Option<DT extends Record<string, any>> = {
11
11
  tableHeaderLast: ShallowRef<PrivateStkTableColumn<DT>[]>;
12
12
  tableHeaders: ShallowRef<PrivateStkTableColumn<DT>[][]>;
13
13
  rowKeyGen: RowKeyGen;
14
+ maxRowSpan: Map<UniqKey, number>;
14
15
  };
15
16
 
16
17
  /** 暂存纵向虚拟滚动的数据 */
@@ -52,7 +53,7 @@ export type VirtualScrollXStore = {
52
53
  const VUE2_SCROLL_TIMEOUT_MS = 200;
53
54
 
54
55
  /**
55
- * 虚拟滚动
56
+ * virtual scroll
56
57
  * @param param0
57
58
  * @returns
58
59
  */
@@ -64,8 +65,8 @@ export function useVirtualScroll<DT extends Record<string, any>>({
64
65
  tableHeaderLast,
65
66
  tableHeaders,
66
67
  rowKeyGen,
68
+ maxRowSpan,
67
69
  }: Option<DT>) {
68
- /** 表头高度 */
69
70
  const tableHeaderHeight = ref(props.headerRowHeight);
70
71
 
71
72
  const virtualScroll = ref<VirtualScrollStore>({
@@ -279,7 +280,6 @@ export function useVirtualScroll<DT extends Record<string, any>>({
279
280
  // 先更新滚动条位置记录,其他地方有依赖。(stripe 时ArrowUp/Down滚动依赖)
280
281
  virtualScroll.value.scrollTop = sTop;
281
282
 
282
- // 非虚拟滚动不往下执行
283
283
  if (!virtual_on.value) {
284
284
  return;
285
285
  }
@@ -325,6 +325,41 @@ export function useVirtualScroll<DT extends Record<string, any>>({
325
325
  endIndex = startIndex + pageSize;
326
326
  }
327
327
 
328
+ if (maxRowSpan.size) {
329
+ // fix startIndex:查找是否有合并行跨越当前startIndex
330
+ let correctedStartIndex = startIndex;
331
+ let correctedEndIndex = endIndex;
332
+
333
+ for (let i = 0; i < startIndex; i++) {
334
+ const row = dataSourceCopyTemp[i];
335
+ if (!row) continue;
336
+ const spanEndIndex = i + (maxRowSpan.get(rowKeyGen(row)) || 1);
337
+ if (spanEndIndex > startIndex) {
338
+ // 找到跨越startIndex的合并行,将startIndex修正为合并行的起始索引
339
+ correctedStartIndex = i;
340
+ if (spanEndIndex > endIndex) {
341
+ // 合并行跨越了整个可视区
342
+ correctedEndIndex = spanEndIndex;
343
+ }
344
+ break;
345
+ }
346
+ }
347
+
348
+ // fix endIndex:查找是否有合并行跨越当前endIndex
349
+ for (let i = correctedStartIndex; i < endIndex; i++) {
350
+ const row = dataSourceCopyTemp[i];
351
+ if (!row) continue;
352
+ const spanEndIndex = i + (maxRowSpan.get(rowKeyGen(row)) || 1);
353
+ if (spanEndIndex > correctedEndIndex) {
354
+ // 找到跨越endIndex的合并行,将endIndex修正为合并行的结束索引
355
+ correctedEndIndex = Math.max(spanEndIndex, correctedEndIndex);
356
+ }
357
+ }
358
+
359
+ startIndex = correctedStartIndex;
360
+ endIndex = correctedEndIndex;
361
+ }
362
+
328
363
  if (stripe && startIndex > 0 && startIndex % 2) {
329
364
  // 斑马纹情况下,每滚动偶数行才加载。防止斑马纹错位。
330
365
  startIndex -= 1; // 奇数-1变成偶数
@@ -338,7 +373,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
338
373
  endIndex = Math.min(endIndex, dataLength);
339
374
 
340
375
  if (startIndex >= endIndex) {
341
- // 兜底,不一定会执行到这里
376
+ // fallback
342
377
  startIndex = endIndex - pageSize;
343
378
  }
344
379
 
@@ -351,20 +386,20 @@ export function useVirtualScroll<DT extends Record<string, any>>({
351
386
  offsetTop = autoRowHeightTop;
352
387
  } else {
353
388
  if (oldStartIndex === startIndex && oldEndIndex === endIndex) {
354
- // 没有变化,不需要更新
389
+ // Not change: not update
355
390
  return;
356
391
  }
357
392
  offsetTop = startIndex * rowHeight;
358
393
  }
359
394
 
360
395
  /**
361
- * 一次滚动大于一页时表示滚动过快,回退优化
396
+ * en: If scroll faster than one page, roll back
362
397
  */
363
398
  if (!optimizeVue2Scroll || sTop <= scrollTop || Math.abs(oldStartIndex - startIndex) >= pageSize) {
364
- // 向上滚动
399
+ // scroll up
365
400
  Object.assign(virtualScroll.value, { startIndex, endIndex, offsetTop });
366
401
  } else {
367
- // vue2向下滚动优化
402
+ // vue2 scroll down optimize
368
403
  virtualScroll.value.endIndex = endIndex;
369
404
  vue2ScrollYTimeout = window.setTimeout(() => {
370
405
  Object.assign(virtualScroll.value, { startIndex, offsetTop });
@@ -374,7 +409,9 @@ export function useVirtualScroll<DT extends Record<string, any>>({
374
409
 
375
410
  let vue2ScrollXTimeout: null | number = null;
376
411
 
377
- /** 通过横向滚动条位置,计算横向虚拟滚动的参数 */
412
+ /**
413
+ * Calculate virtual scroll parameters based on horizontal scroll bar position
414
+ */
378
415
  function updateVirtualScrollX(sLeft = 0) {
379
416
  if (!props.virtualX) return;
380
417
  const tableHeaderLastValue = tableHeaderLast.value;
@@ -384,7 +421,6 @@ export function useVirtualScroll<DT extends Record<string, any>>({
384
421
  const { scrollLeft, containerWidth } = virtualScrollX.value;
385
422
  let startIndex = 0;
386
423
  let offsetLeft = 0;
387
- /** 列宽累加 */
388
424
  let colWidthSum = 0;
389
425
  /** 固定左侧列宽 */
390
426
  let leftColWidthSum = 0;