stk-table-vue 0.2.3 → 0.2.6

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.
@@ -61,7 +61,7 @@
61
61
  :rowspan="virtualX_on ? 1 : col.rowSpan"
62
62
  :colspan="col.colSpan"
63
63
  :style="getCellStyle(1, col, rowIndex)"
64
- :title="col.title"
64
+ :title="getHeaderTitle(col)"
65
65
  :class="[
66
66
  col.sorter ? 'sortable' : '',
67
67
  col.dataIndex === sortCol && sortOrderIndex !== 0 && 'sorter-' + sortSwitchOrder[sortOrderIndex],
@@ -167,7 +167,7 @@
167
167
  >
168
168
  <component :is="col.customCell" v-if="col.customCell" :col="col" :row="row" :cell-value="row[col.dataIndex]" />
169
169
  <div v-else class="table-cell-wrapper" :title="row[col.dataIndex]">
170
- {{ row[col.dataIndex] ?? emptyCellText }}
170
+ {{ row[col.dataIndex] ?? getEmptyCellText(col, row) }}
171
171
  </div>
172
172
  </td>
173
173
  </tr>
@@ -189,7 +189,7 @@
189
189
  * [] 计算的高亮颜色,挂在数据源上对象上,若多个表格使用同一个数据源对象会有问题。需要深拷贝。(解决方案:获取组件uid)
190
190
  * [] highlight-row 颜色不能恢复到active的颜色
191
191
  */
192
- import { CSSProperties, onMounted, ref, shallowRef, toRaw, watch } from 'vue';
192
+ import { CSSProperties, computed, onMounted, ref, shallowRef, toRaw, watch } from 'vue';
193
193
  import { Default_Row_Height } from './const';
194
194
  import { Order, SortConfig, SortOption, SortState, StkTableColumn, UniqKeyProp } from './types/index';
195
195
  import { useAutoResize } from './useAutoResize';
@@ -200,7 +200,7 @@ import { useHighlight } from './useHighlight';
200
200
  import { useKeyboardArrowScroll } from './useKeyboardArrowScroll';
201
201
  import { useThDrag } from './useThDrag';
202
202
  import { useVirtualScroll } from './useVirtualScroll';
203
- import { howDeepTheHeader, tableSort } from './utils';
203
+ import { getColWidth, getColWidthStr, howDeepTheHeader, tableSort } from './utils';
204
204
 
205
205
  /** Generic stands for DataType */
206
206
  type DT = any;
@@ -239,7 +239,7 @@ const props = withDefaults(
239
239
  /** 列唯一键 */
240
240
  colKey?: UniqKeyProp;
241
241
  /** 空值展示文字 */
242
- emptyCellText?: string;
242
+ emptyCellText?: string | ((option: { row: DT; col: StkTableColumn<DT> }) => string);
243
243
  /** 暂无数据兜底高度是否撑满 */
244
244
  noDataFull?: boolean;
245
245
  /** 是否展示暂无数据 */
@@ -258,7 +258,7 @@ const props = withDefaults(
258
258
  * 给行附加className<br>
259
259
  * FIXME: 是否需要优化,因为不传此prop会使表格行一直执行空函数,是否有影响
260
260
  */
261
- rowClassName?: (row: any, i: number) => string;
261
+ rowClassName?: (row: DT, i: number) => string;
262
262
  /**
263
263
  * 列宽是否可拖动<br>
264
264
  * **不要设置**列minWidth,**必须**设置width<br>
@@ -287,6 +287,8 @@ const props = withDefaults(
287
287
  optimizeVue2Scroll?: boolean;
288
288
  /** 排序配置 */
289
289
  sortConfig?: SortConfig<DT>;
290
+ /** 隐藏头部title。可传入dataIndex数组 */
291
+ hideHeaderTitle?: boolean | string[];
290
292
  }>(),
291
293
  {
292
294
  width: '',
@@ -321,7 +323,9 @@ const props = withDefaults(
321
323
  optimizeVue2Scroll: false,
322
324
  sortConfig: () => ({
323
325
  emptyToBottom: false,
326
+ stringLocaleCompare: true,
324
327
  }),
328
+ hideHeaderTitle: false,
325
329
  },
326
330
  );
327
331
 
@@ -442,6 +446,15 @@ const dataSourceCopy = shallowRef<DT[]>([...props.dataSource]);
442
446
  /**高亮帧间隔
443
447
  const highlightStepDuration = Highlight_Color_Change_Freq / 1000 + 's';*/
444
448
 
449
+ /** 空单元格占位字符 */
450
+ const getEmptyCellText = computed(() => {
451
+ if (typeof props.emptyCellText === 'string') {
452
+ return () => props.emptyCellText;
453
+ } else {
454
+ return (col: StkTableColumn<DT>, row: DT) => (props.emptyCellText as any)({ row, col });
455
+ }
456
+ });
457
+
445
458
  /** rowKey缓存 */
446
459
  const rowKeyGenStore = new WeakMap();
447
460
 
@@ -470,11 +483,11 @@ const {
470
483
  initVirtualScrollX,
471
484
  updateVirtualScrollY,
472
485
  updateVirtualScrollX,
473
- } = useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLast });
486
+ } = useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLast, tableHeaders });
474
487
 
475
- const { getFixedStyle } = useFixedStyle({
488
+ const { getFixedStyle } = useFixedStyle<DT>({
476
489
  props,
477
- tableHeaderLast,
490
+ tableHeaders,
478
491
  virtualScroll,
479
492
  virtualScrollX,
480
493
  virtualX_on,
@@ -554,8 +567,8 @@ onMounted(() => {
554
567
  /** 处理默认排序 */
555
568
  function dealDefaultSorter() {
556
569
  if (!props.sortConfig.defaultSort) return;
557
- const { dataIndex, order } = props.sortConfig.defaultSort;
558
- setSorter(dataIndex as string, order);
570
+ const { dataIndex, order, silent } = { silent: false, ...props.sortConfig.defaultSort };
571
+ setSorter(dataIndex as string, order, { force: false, silent });
559
572
  }
560
573
 
561
574
  /**
@@ -587,6 +600,7 @@ function dealColumns() {
587
600
  }
588
601
  /** 所有子节点数量 */
589
602
  let allChildrenLen = 0;
603
+ let allChildrenWidthSum = 0;
590
604
  arr.forEach(col => {
591
605
  // TODO: 继承父节点固定列配置
592
606
  // if (parentFixed) {
@@ -596,10 +610,15 @@ function dealColumns() {
596
610
  col.__PARENT__ = parent;
597
611
  /** 一列中的子节点数量 */
598
612
  let colChildrenLen = 1;
613
+ /** 多级表头的父节点宽度,通过叶子节点宽度计算得到 */
614
+ let colWidth = 0;
599
615
  if (col.children) {
600
616
  // DFS
601
- colChildrenLen = flat(col.children, col, depth + 1 /* , col.fixed */);
617
+ const [len, widthSum] = flat(col.children, col, depth + 1 /* , col.fixed */);
618
+ colChildrenLen = len;
619
+ colWidth = widthSum;
602
620
  } else {
621
+ colWidth = getColWidth(col);
603
622
  tempHeaderLast.push(col); // 没有children的列作为colgroup
604
623
  }
605
624
  // 回溯
@@ -612,9 +631,14 @@ function dealColumns() {
612
631
  if (colSpan !== 1) {
613
632
  col.colSpan = colSpan;
614
633
  }
634
+ if (!props.fixedMode && col.width === void 0) {
635
+ // 列赋值默认列宽。由于有些场景不需要设置width。
636
+ col.width = colWidth + 'px';
637
+ }
615
638
  allChildrenLen += colChildrenLen;
639
+ allChildrenWidthSum += colWidth;
616
640
  });
617
- return allChildrenLen;
641
+ return [allChildrenLen, allChildrenWidthSum];
618
642
  }
619
643
 
620
644
  flat(copyColumn, null);
@@ -646,17 +670,17 @@ function colKeyGen(col: StkTableColumn<DT>) {
646
670
 
647
671
  /** 获取列宽度样式 */
648
672
  function getColWidthStyle(col: StkTableColumn<DT>) {
673
+ const width = getColWidthStr(col);
674
+ const minWidth = getColWidthStr(col, 'minWidth');
675
+ const maxWidth = getColWidthStr(col, 'maxWidth');
649
676
  const style: CSSProperties = {
650
- width: col.width,
651
- minWidth: col.minWidth,
652
- maxWidth: col.maxWidth,
677
+ width,
678
+ minWidth: minWidth ?? width,
679
+ maxWidth: maxWidth ?? width,
653
680
  };
654
681
  if (props.colResizable) {
655
- style.minWidth = col.width;
656
- style.maxWidth = col.width;
657
- } else {
658
- style.minWidth = col.minWidth === void 0 ? col.width : col.minWidth;
659
- style.maxWidth = col.maxWidth === void 0 ? col.width : col.maxWidth;
682
+ style.minWidth = width;
683
+ style.maxWidth = width;
660
684
  }
661
685
 
662
686
  return style;
@@ -686,6 +710,15 @@ function getCellStyle(tagType: 1 | 2, col: StkTableColumn<DT>, depth?: number):
686
710
  return style;
687
711
  }
688
712
 
713
+ /** th title */
714
+ function getHeaderTitle(col: StkTableColumn<DT>): string {
715
+ // 不展示title
716
+ if (props.hideHeaderTitle === true || (Array.isArray(props.hideHeaderTitle) && props.hideHeaderTitle.includes(col.dataIndex))) {
717
+ return '';
718
+ }
719
+ return col.title || '';
720
+ }
721
+
689
722
  /**
690
723
  * 表头点击排序
691
724
  * @param click 是否为点击表头触发
@@ -832,11 +865,12 @@ function setCurrentRow(rowKey: string, option = { silent: false }) {
832
865
  * 设置表头排序状态
833
866
  * @param dataIndex 列字段
834
867
  * @param order 正序倒序
835
- * @param option.sortOption 指定排序参数
868
+ * @param option.sortOption 指定排序参数。同 StkTableColumn 中排序相关字段。建议从columns中find得到。
836
869
  * @param option.sort 是否触发排序-默认true
837
870
  * @param option.silent 是否禁止触发回调-默认true
871
+ * @param option.force 是否触发排序-默认true
838
872
  */
839
- function setSorter(dataIndex: string, order: Order, option: { sortOption?: SortOption<DT>; silent?: boolean; sort?: boolean } = {}) {
873
+ function setSorter(dataIndex: string, order: Order, option: { sortOption?: SortOption<DT>; force?: boolean; silent?: boolean; sort?: boolean } = {}) {
840
874
  const newOption = { silent: true, sortOption: null, sort: true, ...option };
841
875
  sortCol.value = dataIndex;
842
876
  sortOrderIndex.value = sortSwitchOrder.indexOf(order);
@@ -844,7 +878,7 @@ function setSorter(dataIndex: string, order: Order, option: { sortOption?: SortO
844
878
  if (newOption.sort && dataSourceCopy.value?.length) {
845
879
  // 如果表格有数据,则进行排序
846
880
  const column = newOption.sortOption || tableHeaderLast.value.find(it => it.dataIndex === sortCol.value);
847
- if (column) onColumnSort(column, false, { force: true, emit: !newOption.silent });
881
+ if (column) onColumnSort(column, false, { force: option.force ?? true, emit: !newOption.silent });
848
882
  else console.warn('Can not find column by dataIndex:', sortCol.value);
849
883
  }
850
884
  return dataSourceCopy.value;
@@ -77,9 +77,19 @@ export type UniqKeyProp = UniqKey | UniqKeyFun;
77
77
  export type SortConfig<T extends Record<string, any>> = {
78
78
  /** 空值始终排在列表末尾 */
79
79
  emptyToBottom?: boolean;
80
- /** 默认排序(1.初始化时触发 2.排序方向为null时触发) */
80
+ /**
81
+ * 默认排序(1.初始化时触发 2.排序方向为null时触发)
82
+ * 类似onMounted时,调用setSorter点了下表头。
83
+ */
81
84
  defaultSort?: {
82
85
  dataIndex: keyof T;
83
86
  order: Order;
87
+ /** 是否禁止触发sort-change事件。默认false,表示触发事件。 */
88
+ silent?: boolean;
84
89
  };
90
+ /**
91
+ * string排序是否使用 String.prototype.localCompare
92
+ * 默认true (&$&应该false)
93
+ */
94
+ stringLocaleCompare?: boolean;
85
95
  };
@@ -4,9 +4,9 @@ import { StkTableColumn } from './types';
4
4
  import { VirtualScrollStore, VirtualScrollXStore } from './useVirtualScroll';
5
5
  import { getColWidth } from './utils';
6
6
 
7
- type Options = {
7
+ type Options<T extends Record<string, any>> = {
8
8
  props: any;
9
- tableHeaderLast: Ref<StkTableColumn<any>[]>;
9
+ tableHeaders: Ref<StkTableColumn<T>[][]>;
10
10
  virtualScroll: Ref<VirtualScrollStore>;
11
11
  virtualScrollX: Ref<VirtualScrollXStore>;
12
12
  virtualX_on: Ref<boolean>;
@@ -17,33 +17,52 @@ type Options = {
17
17
  * @param param0
18
18
  * @returns
19
19
  */
20
- export function useFixedStyle({ props, tableHeaderLast, virtualScroll, virtualScrollX, virtualX_on, virtualX_offsetRight }: Options) {
20
+ export function useFixedStyle<DT extends Record<string, any>>({
21
+ props,
22
+ tableHeaders,
23
+ virtualScroll,
24
+ virtualScrollX,
25
+ virtualX_on,
26
+ virtualX_offsetRight,
27
+ }: Options<DT>) {
21
28
  const fixedColumnsPositionStore = computed(() => {
22
- const store: Record<string, number> = {};
23
- const cols = [...tableHeaderLast.value];
24
- let left = 0;
25
- /**遍历右侧fixed时,因为left已经遍历过一次了。所以,可以拿到right遍历边界 */
26
- let rightStartIndex = 0;
27
- for (let i = 0; i < cols.length; i++) {
28
- const item = cols[i];
29
- if (item.fixed === 'left') {
30
- store[item.dataIndex] = left;
31
- left += getColWidth(item);
32
- }
33
- if (!rightStartIndex && item.fixed === 'right') {
34
- rightStartIndex = i;
29
+ /** dataIndex 作为唯一标识 */
30
+ const colKeyStore: Record<string, number> = {};
31
+ /** 没有dataIndex 的多级表头列,使用对象引用做标识 */
32
+ const refStore = new WeakMap<StkTableColumn<DT>, number>();
33
+ tableHeaders.value.forEach(cols => {
34
+ let left = 0;
35
+ /**遍历右侧fixed时,因为left已经遍历过一次了。所以,可以拿到right遍历边界 */
36
+ let rightStartIndex = 0;
37
+ for (let i = 0; i < cols.length; i++) {
38
+ const item = cols[i];
39
+ if (item.fixed === 'left') {
40
+ if (item.dataIndex) {
41
+ colKeyStore[item.dataIndex] = left;
42
+ } else {
43
+ refStore.set(item, left);
44
+ }
45
+ left += getColWidth(item);
46
+ }
47
+ if (!rightStartIndex && item.fixed === 'right') {
48
+ rightStartIndex = i;
49
+ }
35
50
  }
36
- }
37
- let right = 0;
38
- for (let i = cols.length - 1; i >= rightStartIndex; i--) {
39
- const item = cols[i];
40
- if (item.fixed === 'right') {
41
- store[item.dataIndex] = right;
42
- right += getColWidth(item);
51
+ let right = 0;
52
+ for (let i = cols.length - 1; i >= rightStartIndex; i--) {
53
+ const item = cols[i];
54
+ if (item.fixed === 'right') {
55
+ if (item.dataIndex) {
56
+ colKeyStore[item.dataIndex] = right;
57
+ } else {
58
+ refStore.set(item, right);
59
+ }
60
+ right += getColWidth(item);
61
+ }
43
62
  }
44
- }
63
+ });
45
64
 
46
- return store;
65
+ return { refStore, colKeyStore };
47
66
  });
48
67
  /**
49
68
  * 固定列的style
@@ -52,9 +71,10 @@ export function useFixedStyle({ props, tableHeaderLast, virtualScroll, virtualSc
52
71
  * @param depth 深度。tagType = 1时使用
53
72
  */
54
73
  function getFixedStyle(tagType: 1 | 2, col: StkTableColumn<any>, depth = 0): CSSProperties {
55
- const { fixed, dataIndex } = col;
74
+ const { fixed } = col;
56
75
  const isFixedLeft = fixed === 'left';
57
76
  const style: CSSProperties = {};
77
+ const { colKeyStore, refStore } = fixedColumnsPositionStore.value;
58
78
  // TD
59
79
  if (Is_Legacy_Mode) {
60
80
  style.position = 'relative';
@@ -83,10 +103,11 @@ export function useFixedStyle({ props, tableHeaderLast, virtualScroll, virtualSc
83
103
  style.right = `${virtualX_offsetRight.value}px`;
84
104
  }
85
105
  } else {
106
+ const lr = (col.dataIndex ? colKeyStore[col.dataIndex] : refStore.get(col)) + 'px';
86
107
  if (isFixedLeft) {
87
- style.left = fixedColumnsPositionStore.value[dataIndex] + 'px';
108
+ style.left = lr;
88
109
  } else {
89
- style.right = fixedColumnsPositionStore.value[dataIndex] + 'px';
110
+ style.right = lr;
90
111
  }
91
112
  }
92
113
  }
@@ -30,9 +30,9 @@ export function useHighlight({ props, tableContainer }: Params) {
30
30
  */
31
31
  const highlightRowStore = ref<Record<UniqKey, HighlightRowStore>>({});
32
32
 
33
- const highlightFrom = Highlight_Color[props.theme].from;
34
- const highlightTo = Highlight_Color[props.theme].to;
35
- const highlightInter = computed(() => interpolateRgb(highlightFrom, highlightTo));
33
+ const highlightFrom = computed(() => Highlight_Color[props.theme].from);
34
+ const highlightTo = computed(() => Highlight_Color[props.theme].to);
35
+ const highlightInter = computed(() => interpolateRgb(highlightFrom.value, highlightTo.value));
36
36
 
37
37
  /** 存放高亮行的key*/
38
38
  const highlightDimRowKeys = new Set<UniqKey>();
@@ -76,6 +76,9 @@ export function useHighlight({ props, tableContainer }: Params) {
76
76
  }
77
77
  });
78
78
 
79
+ // $*$ 兼容vue2响应
80
+ highlightRowStore.value = { ...highlightRowStore.value };
81
+
79
82
  if (highlightDimRowKeys.size > 0) {
80
83
  // 还有高亮的行,则下一次循环
81
84
  recursion();
@@ -44,11 +44,15 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
44
44
  if (!isMouseOver) return; // 不悬浮还是要触发键盘事件的
45
45
  e.preventDefault(); // 不触发键盘默认的箭头事件
46
46
 
47
- const { scrollTop, rowHeight, pageSize } = virtualScroll.value;
47
+ const { scrollTop, rowHeight, containerHeight } = virtualScroll.value;
48
48
  const { scrollLeft } = virtualScrollX.value;
49
49
  const { headless, headerRowHeight } = props;
50
- /**表头高度 */
50
+
51
+ // 这里不用virtualScroll 中的pageSize,因为我需要上一页的最后一条放在下一页的第一条
51
52
  const headerHeight = headless ? 0 : tableHeaders.value.length * (headerRowHeight || rowHeight);
53
+ /** 表体的page */
54
+ const bodyPageSize = Math.floor((containerHeight - headerHeight) / rowHeight);
55
+
52
56
  if (e.code === SCROLL_CODES[0]) {
53
57
  scrollTo(scrollTop - rowHeight, null);
54
58
  } else if (e.code === SCROLL_CODES[1]) {
@@ -58,9 +62,9 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
58
62
  } else if (e.code === SCROLL_CODES[3]) {
59
63
  scrollTo(null, scrollLeft - rowHeight);
60
64
  } else if (e.code === SCROLL_CODES[4]) {
61
- scrollTo(scrollTop - rowHeight * pageSize - headerHeight, null);
65
+ scrollTo(scrollTop - rowHeight * bodyPageSize + headerHeight, null);
62
66
  } else if (e.code === SCROLL_CODES[5]) {
63
- scrollTo(scrollTop + rowHeight * pageSize - headerHeight, null);
67
+ scrollTo(scrollTop + rowHeight * bodyPageSize - headerHeight, null);
64
68
  }
65
69
  }
66
70
 
@@ -4,10 +4,11 @@ import { StkTableColumn } from './types';
4
4
  import { getColWidth } from './utils';
5
5
 
6
6
  type Option<DT extends Record<string, any>> = {
7
- tableContainer: Ref<HTMLElement | undefined>;
8
7
  props: any;
8
+ tableContainer: Ref<HTMLElement | undefined>;
9
9
  dataSourceCopy: ShallowRef<DT[]>;
10
10
  tableHeaderLast: Ref<StkTableColumn<DT>[]>;
11
+ tableHeaders: Ref<StkTableColumn<DT>[][]>;
11
12
  };
12
13
 
13
14
  /** 暂存纵向虚拟滚动的数据 */
@@ -49,7 +50,13 @@ const VUE2_SCROLL_TIMEOUT_MS = 200;
49
50
  * @param param0
50
51
  * @returns
51
52
  */
52
- export function useVirtualScroll<DT extends Record<string, any>>({ props, tableContainer, dataSourceCopy, tableHeaderLast }: Option<DT>) {
53
+ export function useVirtualScroll<DT extends Record<string, any>>({
54
+ props,
55
+ tableContainer,
56
+ dataSourceCopy,
57
+ tableHeaderLast,
58
+ tableHeaders,
59
+ }: Option<DT>) {
53
60
  const virtualScroll = ref<VirtualScrollStore>({
54
61
  containerHeight: 0,
55
62
  rowHeight: props.rowHeight,
@@ -140,10 +147,14 @@ export function useVirtualScroll<DT extends Record<string, any>>({ props, tableC
140
147
  } else {
141
148
  containerHeight = offsetHeight || Default_Table_Height;
142
149
  }
143
- Object.assign(virtualScroll.value, {
144
- containerHeight,
145
- pageSize: Math.ceil(containerHeight / rowHeight) + 1, // 这里最终+1,因为headless=true无头时,需要上下各预渲染一行。
146
- });
150
+ const { headless, headerRowHeight } = props;
151
+ let pageSize = Math.ceil(containerHeight / rowHeight);
152
+ if (!headless) {
153
+ /** 表头高度占几行表体高度数 */
154
+ const headerToBodyRowHeightCount = Math.floor((tableHeaders.value.length * (headerRowHeight || rowHeight)) / rowHeight);
155
+ pageSize -= headerToBodyRowHeightCount; //减去表头行数
156
+ }
157
+ Object.assign(virtualScroll.value, { containerHeight, pageSize });
147
158
  updateVirtualScrollY(scrollTop);
148
159
  }
149
160
 
@@ -168,9 +179,30 @@ export function useVirtualScroll<DT extends Record<string, any>>({ props, tableC
168
179
  /** 通过滚动条位置,计算虚拟滚动的参数 */
169
180
  function updateVirtualScrollY(sTop = 0) {
170
181
  const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex } = virtualScroll.value;
171
- const startIndex = Math.floor(sTop / rowHeight);
172
- const offsetTop = startIndex * rowHeight; // startIndex之前的高度
182
+ // 先更新滚动条位置记录,其他地方可能有依赖。(stripe 时ArrowUp/Down滚动依赖)
183
+ virtualScroll.value.scrollTop = sTop;
184
+ let startIndex = Math.floor(sTop / rowHeight);
185
+ if (props.stripe) {
186
+ startIndex -= 1; //预渲染1行
187
+ }
188
+ if (startIndex < 0) {
189
+ startIndex = 0;
190
+ }
191
+ if (props.stripe && startIndex !== 0) {
192
+ const scrollRows = Math.abs(oldStartIndex - startIndex);
193
+ // 斑马纹情况下,每滚动偶数行才加载。防止斑马纹错位。
194
+ if (scrollRows < 2) {
195
+ return;
196
+ } else if (scrollRows % 2) {
197
+ startIndex -= 1; // 奇数-1变成偶数
198
+ }
199
+ }
173
200
  let endIndex = startIndex + pageSize;
201
+ if (props.stripe) {
202
+ // 由于上方预渲染一行,这里也要预渲染1+1行
203
+ endIndex += 2;
204
+ }
205
+ const offsetTop = startIndex * rowHeight; // startIndex之前的高度
174
206
  if (endIndex > dataSourceCopy.value.length) {
175
207
  endIndex = dataSourceCopy.value.length; // 溢出index修正
176
208
  }
@@ -184,13 +216,12 @@ export function useVirtualScroll<DT extends Record<string, any>>({ props, tableC
184
216
  // 向上滚动
185
217
  Object.assign(virtualScroll.value, {
186
218
  startIndex,
187
- offsetTop,
188
219
  endIndex,
189
- scrollTop: sTop,
220
+ offsetTop,
190
221
  });
191
222
  } else {
192
223
  // vue2向下滚动优化
193
- Object.assign(virtualScroll.value, { endIndex, scrollTop: sTop });
224
+ virtualScroll.value.endIndex = endIndex;
194
225
  vue2ScrollYTimeout = window.setTimeout(() => {
195
226
  Object.assign(virtualScroll.value, { startIndex, offsetTop });
196
227
  }, VUE2_SCROLL_TIMEOUT_MS);