stk-table-vue 0.3.3 → 0.3.4

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/README.md CHANGED
@@ -16,7 +16,7 @@ repo:
16
16
  - [x] 虚拟滚动默认通过js计算行高亮背景色,可通过 `useCss` 设置为css @keyframe实现 。
17
17
  - [x] 支持配置高亮参数(持续时间,颜色,频率(虚拟滚动))。(`v0.2.9`)
18
18
  - [x] `setHighlightDimRow`/`setHighlightCellRow`支持自定义高亮css类名。(`v0.2.9`)
19
- - [x] 使用 `Web Animations API` 实现高亮。
19
+ - [x] 使用 `Web Animations API` 实现高亮。(`v0.3.4` 变更为默认值)
20
20
  * [x] 虚拟滚动。
21
21
  - [x] 纵向。
22
22
  - [x] 横向(必须设置列宽)。
@@ -223,7 +223,7 @@ export type StkProps = {
223
223
  highlightConfig?: {
224
224
  /** 高亮持续时间(s) */
225
225
  duration?: number;
226
- /** 高亮帧率(虚拟滚动生效) */
226
+ /** 高亮帧率*/
227
227
  fps?: number;
228
228
  };
229
229
  /** 序号列配置 */
@@ -549,13 +549,20 @@ export type SortConfig<T extends Record<string, any>> = {
549
549
  ### 鼠标悬浮表头时,不展示title
550
550
  * 将 `StkTableColumn` 中的 `title` 字段置为 "" 空字符串。这样th中就没有title了。
551
551
  * 使用 `StkTableColumn` 中的 `customHeaderCell` 属性中,自定义表头渲染。
552
- ### 高亮性能
553
- * 在虚拟滚动下高亮强制使用css @keyframes 实现动画。`setHighlightDimRow`/`setHighlightCellRow` 最后一个参数传入 `{method: 'css'}` 即可。(滚动后动画会中断)
554
- * 指定 `{method:'animation'}` 在虚拟滚动下使用animation api实现动画。好处是动画流畅,且滚动后动画不中断。
555
- * 配置 `props.highlightConfig.fps` 指定高亮帧率。降低帧率有利于性能。
556
552
  ### 性能
557
- * 配置 `props.cellFixedMode` 为 `relative` 时,将使用相对定位实现固定列与固定表头,相较于`sticky`的实现,渲染合成层更少,性能更好。
553
+ #### highlight
554
+ * 在虚拟滚动下高亮强制使用 `css @keyframes` 实现动画。`setHighlightDimRow`/`setHighlightCellRow` 最后一个参数传入 `{method: 'css'}` 即可。(滚动后动画会中断)
555
+ * 指定 `{method:'animation'}` 在虚拟滚动下使用animation api实现动画。好处是动画流畅,且滚动后动画不中断。坏处是不支持帧率配置。
556
+ * 配置 `props.highlightConfig.fps` 指定高亮帧率。降低帧率有利于性能。
557
+ #### relative fixed
558
+ * 配置 `props.cellFixedMode` 为 `relative` 时,将使用相对定位实现固定列与固定表头,相较于`sticky`的实现,渲染合成层更少。
558
559
  * 问题:若开启了纵向虚拟滚动,不开启横向虚拟滚动,且不设置某些列宽时。如果纵向滚动导致某些列宽变化,则会导致右侧固定列计算错误。
560
+ #### tr 分层
561
+ * 通过css选择器将 stk-table tbody tr 配置 `transform:translateZ(0)` 对每行 tr 进行分层。在 `customCell` 较多且复杂时,尝试开启此功能可能对性能有帮助。
559
562
 
560
563
  ## Other
561
564
  * `$*$` 兼容注释
565
+
566
+
567
+ ### Planed removal APi
568
+ * `setHighlightDimRow` 中的 `method="js"`。观察animation Api 是否足够满足使用场景。若足够满足计划在后期移除,并且可以移除 `d3-interpolate` 依赖。
@@ -186,13 +186,13 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
186
186
  /** 设置高亮渐暗单元格 */
187
187
  setHighlightDimCell: (rowKeyValue: string, dataIndex: string, option?: {
188
188
  className?: string | undefined;
189
- method?: "css" | "animation" | undefined;
189
+ method?: "animation" | "css" | undefined;
190
190
  keyframe?: Keyframe[] | PropertyIndexedKeyframes | null | undefined;
191
191
  duration?: number | undefined;
192
192
  }) => void;
193
193
  /** 设置高亮渐暗行 */
194
194
  setHighlightDimRow: (rowKeyValues: UniqKey[], option?: {
195
- method?: "css" | "animation" | "js" | undefined;
195
+ method?: "animation" | "css" | "js" | undefined;
196
196
  useCss?: boolean | undefined;
197
197
  className?: string | undefined;
198
198
  keyframe?: Keyframe[] | PropertyIndexedKeyframes | null | undefined;
@@ -9,9 +9,9 @@ type Params = {
9
9
  * 高亮单元格,行
10
10
  */
11
11
  export declare function useHighlight({ props, stkTableId, tableContainerRef }: Params): {
12
- highlightSteps: number;
12
+ highlightSteps: number | null;
13
13
  setHighlightDimRow: (rowKeyValues: UniqKey[], option?: {
14
- method?: 'css' | 'animation' | 'js';
14
+ method?: 'animation' | 'css' | 'js';
15
15
  /** @deprecated 请使用method */
16
16
  useCss?: boolean;
17
17
  className?: string;
@@ -20,7 +20,7 @@ export declare function useHighlight({ props, stkTableId, tableContainerRef }: P
20
20
  }) => void;
21
21
  setHighlightDimCell: (rowKeyValue: string, dataIndex: string, option?: {
22
22
  className?: string;
23
- method?: 'css' | 'animation';
23
+ method?: 'animation' | 'css';
24
24
  keyframe?: Parameters<Animatable['animate']>['0'];
25
25
  duration?: number;
26
26
  }) => void;
@@ -510,13 +510,13 @@ function useFixedStyle({
510
510
  }
511
511
  function useHighlight({ props, stkTableId, tableContainerRef }) {
512
512
  const config = props.highlightConfig;
513
- const highlightDuration = config.duration ? config.duration * 1e3 : HIGHLIGHT_DURATION;
514
- const highlightFrequency = config.fps ? 1e3 / config.fps : HIGHLIGHT_FREQ;
515
513
  const highlightColor = {
516
514
  light: HIGHLIGHT_COLOR.light,
517
515
  dark: HIGHLIGHT_COLOR.dark
518
516
  };
519
- const highlightSteps = highlightDuration / highlightFrequency;
517
+ const highlightDuration = config.duration ? config.duration * 1e3 : HIGHLIGHT_DURATION;
518
+ const highlightFrequency = config.fps && config.fps > 0 ? 1e3 / config.fps : null;
519
+ const highlightSteps = highlightFrequency ? Math.round(highlightDuration / highlightFrequency) : null;
520
520
  const highlightFrom = computed(() => highlightColor[props.theme].from);
521
521
  const highlightTo = computed(() => highlightColor[props.theme].to);
522
522
  const highlightInter = computed(() => interpolateRgb(highlightFrom.value, highlightTo.value));
@@ -526,6 +526,13 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
526
526
  let calcHighlightDimLoopAnimation = false;
527
527
  const highlightDimRowsTimeout = /* @__PURE__ */ new Map();
528
528
  const highlightDimCellsTimeout = /* @__PURE__ */ new Map();
529
+ const defaultHighlightDimOption = (() => {
530
+ const keyframe = { backgroundColor: [highlightFrom.value, highlightTo.value] };
531
+ if (highlightSteps) {
532
+ keyframe.easing = `steps(${highlightSteps})`;
533
+ }
534
+ return { duration: highlightDuration, keyframe };
535
+ })();
529
536
  function calcRowHighlightLoop() {
530
537
  if (calcHighlightDimLoopAnimation)
531
538
  return;
@@ -577,20 +584,16 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
577
584
  calcHighlightDimLoopJs = false;
578
585
  highlightDimRowsJs.clear();
579
586
  }
580
- }, highlightFrequency);
587
+ }, highlightFrequency || HIGHLIGHT_FREQ);
581
588
  };
582
589
  recursion();
583
590
  }
584
- const defaultHighlightDimOption = {
585
- keyframe: [{ backgroundColor: highlightFrom.value }, { backgroundColor: highlightTo.value }],
586
- duration: highlightDuration
587
- };
588
591
  function setHighlightDimCell(rowKeyValue, dataIndex, option = {}) {
589
592
  var _a;
590
593
  const cellEl = (_a = tableContainerRef.value) == null ? void 0 : _a.querySelector(`[data-row-key="${rowKeyValue}"]>[data-index="${dataIndex}"]`);
591
594
  const { className, method, duration, keyframe } = {
592
595
  className: HIGHLIGHT_CELL_CLASS,
593
- method: "css",
596
+ method: "animation",
594
597
  ...defaultHighlightDimOption,
595
598
  ...option
596
599
  };
@@ -607,7 +610,7 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
607
610
  rowKeyValues = [rowKeyValues];
608
611
  const { className, method, useCss, keyframe, duration } = {
609
612
  className: HIGHLIGHT_ROW_CLASS,
610
- method: props.virtual ? "js" : "css",
613
+ method: "animation",
611
614
  ...defaultHighlightDimOption,
612
615
  ...option
613
616
  };
@@ -910,12 +913,7 @@ function useVirtualScroll({
910
913
  return;
911
914
  const { offsetHeight, scrollTop } = tableContainerRef.value || {};
912
915
  const { rowHeight } = virtualScroll.value;
913
- let containerHeight;
914
- if (typeof height === "number") {
915
- containerHeight = height;
916
- } else {
917
- containerHeight = offsetHeight || DEFAULT_TABLE_HEIGHT;
918
- }
916
+ const containerHeight = height ?? (offsetHeight || DEFAULT_TABLE_HEIGHT);
919
917
  const { headless, headerRowHeight } = props;
920
918
  let pageSize = Math.ceil(containerHeight / rowHeight);
921
919
  if (!headless) {
@@ -942,17 +940,12 @@ function useVirtualScroll({
942
940
  if (!virtual_on.value)
943
941
  return;
944
942
  let startIndex = Math.floor(sTop / rowHeight);
945
- if (props.stripe) {
946
- startIndex -= 1;
947
- }
948
943
  if (startIndex < 0) {
949
944
  startIndex = 0;
950
945
  }
951
946
  if (props.stripe && startIndex !== 0) {
952
947
  const scrollRows = Math.abs(oldStartIndex - startIndex);
953
- if (scrollRows < 2) {
954
- return;
955
- } else if (scrollRows % 2) {
948
+ if (scrollRows % 2) {
956
949
  startIndex -= 1;
957
950
  }
958
951
  }
@@ -984,17 +977,18 @@ function useVirtualScroll({
984
977
  if (!props.virtualX)
985
978
  return;
986
979
  const headerLength = (_a = tableHeaderLast.value) == null ? void 0 : _a.length;
987
- const { scrollLeft } = virtualScrollX.value;
988
980
  if (!headerLength)
989
981
  return;
982
+ const { scrollLeft } = virtualScrollX.value;
990
983
  let startIndex = 0;
991
984
  let offsetLeft = 0;
992
985
  let colWidthSum = 0;
993
986
  let leftColWidthSum = 0;
987
+ let leftFirstColRestWidth = 0;
994
988
  for (let colIndex = 0; colIndex < headerLength; colIndex++) {
995
- startIndex++;
996
989
  const col = tableHeaderLast.value[colIndex];
997
990
  const colWidth = getCalculatedColWidth(col);
991
+ startIndex++;
998
992
  if (col.fixed === "left") {
999
993
  leftColWidthSum += colWidth;
1000
994
  continue;
@@ -1003,10 +997,11 @@ function useVirtualScroll({
1003
997
  if (colWidthSum >= sLeft) {
1004
998
  offsetLeft = colWidthSum - colWidth;
1005
999
  startIndex--;
1000
+ leftFirstColRestWidth = colWidthSum - sLeft;
1006
1001
  break;
1007
1002
  }
1008
1003
  }
1009
- colWidthSum = 0;
1004
+ colWidthSum = leftFirstColRestWidth;
1010
1005
  const containerWidth = virtualScrollX.value.containerWidth - leftColWidthSum;
1011
1006
  let endIndex = headerLength;
1012
1007
  for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {
@@ -1570,16 +1565,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1570
1565
  "text-overflow": props.showOverflow,
1571
1566
  "header-text-overflow": props.showHeaderOverflow
1572
1567
  }]),
1573
- style: normalizeStyle([
1574
- _ctx.virtual && {
1575
- "--row-height": unref(virtualScroll).rowHeight + "px",
1576
- "--header-row-height": (props.headerRowHeight || props.rowHeight) + "px"
1577
- },
1578
- {
1579
- "--highlight-duration": props.highlightConfig.duration && props.highlightConfig.duration + "s",
1580
- "--highlight-timing-function": unref(highlightSteps) ? `steps(${unref(highlightSteps)})` : ""
1581
- }
1582
- ]),
1568
+ style: normalizeStyle({
1569
+ "--row-height": unref(virtualScroll).rowHeight + "px",
1570
+ "--header-row-height": (props.headerRowHeight || props.rowHeight) + "px",
1571
+ "--highlight-duration": props.highlightConfig.duration && props.highlightConfig.duration + "s",
1572
+ "--highlight-timing-function": unref(highlightSteps) ? `steps(${unref(highlightSteps)})` : ""
1573
+ }),
1583
1574
  onScroll: onTableScroll,
1584
1575
  onWheel: onTableWheel
1585
1576
  }, [
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "stk-table-vue",
3
- "version": "0.3.3",
4
- "description": "Simple realtime virtual table for vue3&vue2.7",
3
+ "version": "0.3.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",
7
7
  "packageManager": "pnpm@8.14.3",
@@ -17,8 +17,13 @@
17
17
  "keywords": [
18
18
  "virtual table",
19
19
  "vue",
20
+ "vue2",
21
+ "vue3",
20
22
  "highlight",
21
- "sticky"
23
+ "sticky",
24
+ "virtual",
25
+ "table",
26
+ "list"
22
27
  ],
23
28
  "files": [
24
29
  "lib",
@@ -18,16 +18,12 @@
18
18
  'text-overflow': props.showOverflow,
19
19
  'header-text-overflow': props.showHeaderOverflow,
20
20
  }"
21
- :style="[
22
- virtual && {
23
- '--row-height': virtualScroll.rowHeight + 'px',
24
- '--header-row-height': (props.headerRowHeight || props.rowHeight) + 'px',
25
- },
26
- {
27
- '--highlight-duration': props.highlightConfig.duration && props.highlightConfig.duration + 's',
28
- '--highlight-timing-function': highlightSteps ? `steps(${highlightSteps})` : '',
29
- },
30
- ]"
21
+ :style="{
22
+ '--row-height': virtualScroll.rowHeight + 'px',
23
+ '--header-row-height': (props.headerRowHeight || props.rowHeight) + 'px',
24
+ '--highlight-duration': props.highlightConfig.duration && props.highlightConfig.duration + 's',
25
+ '--highlight-timing-function': highlightSteps ? `steps(${highlightSteps})` : '',
26
+ }"
31
27
  @scroll="onTableScroll"
32
28
  @wheel="onTableWheel"
33
29
  >
@@ -11,6 +11,7 @@ export const HIGHLIGHT_COLOR = {
11
11
  };
12
12
  /** 高亮持续时间 */
13
13
  export const HIGHLIGHT_DURATION = 2000;
14
+
14
15
  /** 高亮变更频率 */
15
16
  export const HIGHLIGHT_FREQ = 1000 / 30;
16
17
 
@@ -26,18 +26,17 @@ type HighlightDimRowStore = {
26
26
  export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
27
27
  const config: HighlightConfig = props.highlightConfig;
28
28
 
29
- /** 持续时间 */
30
- const highlightDuration = config.duration ? config.duration * 1000 : HIGHLIGHT_DURATION;
31
- /** 高亮频率(仅虚拟滚动生效) */
32
- const highlightFrequency = config.fps ? 1000 / config.fps : HIGHLIGHT_FREQ;
33
29
  /** 高亮颜色 */
34
30
  const highlightColor = {
35
31
  light: HIGHLIGHT_COLOR.light,
36
32
  dark: HIGHLIGHT_COLOR.dark,
37
33
  };
38
-
39
- /** css 高亮的次数,用于css animation steps() */
40
- const highlightSteps = highlightDuration / highlightFrequency;
34
+ /** 持续时间 */
35
+ const highlightDuration = config.duration ? config.duration * 1000 : HIGHLIGHT_DURATION;
36
+ /** 高亮频率*/
37
+ const highlightFrequency = config.fps && config.fps > 0 ? 1000 / config.fps : null;
38
+ /** 高亮帧数(非帧率),用于 timing-function: steps() */
39
+ const highlightSteps = highlightFrequency ? Math.round(highlightDuration / highlightFrequency) : null;
41
40
  /** 高亮开始 */
42
41
  const highlightFrom = computed(() => highlightColor[props.theme as 'light' | 'dark'].from);
43
42
  /** 高亮结束 */
@@ -66,6 +65,15 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
66
65
  /** 高亮后渐暗的单元格定时器 */
67
66
  const highlightDimCellsTimeout = new Map();
68
67
 
68
+ /** 高亮函数的默认参数 */
69
+ const defaultHighlightDimOption = (() => {
70
+ const keyframe: PropertyIndexedKeyframes = { backgroundColor: [highlightFrom.value, highlightTo.value] };
71
+ if (highlightSteps) {
72
+ keyframe.easing = `steps(${highlightSteps})`;
73
+ }
74
+ return { duration: highlightDuration, keyframe };
75
+ })();
76
+
69
77
  /**
70
78
  * 计算高亮渐暗颜色的循环
71
79
  */
@@ -130,22 +138,16 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
130
138
  calcHighlightDimLoopJs = false;
131
139
  highlightDimRowsJs.clear(); // TODO: 是否需要 清除
132
140
  }
133
- }, highlightFrequency);
141
+ }, highlightFrequency || HIGHLIGHT_FREQ);
134
142
  };
135
143
  recursion();
136
144
  }
137
145
 
138
- /** 高亮函数的默认参数 */
139
- const defaultHighlightDimOption = {
140
- keyframe: [{ backgroundColor: highlightFrom.value }, { backgroundColor: highlightTo.value }],
141
- duration: highlightDuration,
142
- };
143
-
144
146
  /**
145
- * 高亮一个单元格
147
+ * 高亮一个单元格。暂不支持虚拟滚动高亮状态记忆。
146
148
  * @param rowKeyValue 一行的key
147
149
  * @param dataIndex 列key
148
- * @param options.method css-使用css渲染,animation-使用animation api。默认css;
150
+ * @param options.method css-使用css渲染,animation-使用animation api。默认animation;
149
151
  * @param option.className 自定义css动画的class。
150
152
  * @param option.keyframe 同Keyframe https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
151
153
  * @param option.duration 动画时长。method='css'状态下,用于移除class,如果传入了className则需要与自定义的动画时间一致。
@@ -153,13 +155,12 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
153
155
  function setHighlightDimCell(
154
156
  rowKeyValue: string,
155
157
  dataIndex: string,
156
- option: { className?: string; method?: 'css' | 'animation'; keyframe?: Parameters<Animatable['animate']>['0']; duration?: number } = {},
158
+ option: { className?: string; method?: 'animation' | 'css'; keyframe?: Parameters<Animatable['animate']>['0']; duration?: number } = {},
157
159
  ) {
158
- // TODO: 支持动态计算高亮颜色。不易实现。需记录每一个单元格的颜色情况。
159
160
  const cellEl = tableContainerRef.value?.querySelector<HTMLElement>(`[data-row-key="${rowKeyValue}"]>[data-index="${dataIndex}"]`);
160
161
  const { className, method, duration, keyframe } = {
161
162
  className: HIGHLIGHT_CELL_CLASS,
162
- method: 'css',
163
+ method: 'animation',
163
164
  ...defaultHighlightDimOption,
164
165
  ...option,
165
166
  };
@@ -174,15 +175,15 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
174
175
  /**
175
176
  * 高亮一行
176
177
  * @param rowKeyValues 行唯一键的数组
177
- * @param option.method css-使用css渲染,animation-使用animation api,js-使用js计算颜色
178
+ * @param option.method css-使用css渲染,animation-使用animation api,js-使用js计算颜色。默认animation
178
179
  * @param option.className 自定义css动画的class。
179
- * @param option.keyframe 同Keyframe,无法控制帧率。 https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
180
+ * @param option.keyframe 同Keyframe https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
180
181
  * @param option.duration 动画时长。method='css'状态下,用于移除class,如果传入了className则需要与自定义的动画时间一致。。
181
182
  */
182
183
  function setHighlightDimRow(
183
184
  rowKeyValues: UniqKey[],
184
185
  option: {
185
- method?: 'css' | 'animation' | 'js';
186
+ method?: 'animation' | 'css' | 'js';
186
187
  /** @deprecated 请使用method */
187
188
  useCss?: boolean;
188
189
  className?: string;
@@ -193,7 +194,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
193
194
  if (!Array.isArray(rowKeyValues)) rowKeyValues = [rowKeyValues];
194
195
  const { className, method, useCss, keyframe, duration } = {
195
196
  className: HIGHLIGHT_ROW_CLASS,
196
- method: props.virtual ? 'js' : 'css',
197
+ method: 'animation',
197
198
  ...defaultHighlightDimOption,
198
199
  ...option,
199
200
  };
@@ -234,7 +235,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
234
235
 
235
236
  /**
236
237
  * 使用css @keyframes动画,实现高亮行动画
237
- * 此方案作为兼容方式。v0.3.0 将使用Element.animate 接口实现动画。
238
+ * 此方案作为兼容方式。v0.3.4 将使用Element.animate 接口实现动画。
238
239
  */
239
240
  function highlightRowsInCssKeyframe(rowKeyValues: UniqKey[], className: string, duration: number) {
240
241
  /**是否需要重绘 */
@@ -267,7 +268,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
267
268
 
268
269
  /**
269
270
  * 使用css @keyframes动画,实现高亮单元格动画
270
- * 此方案作为兼容方式。v0.3.0 将使用Element.animate 接口实现动画。
271
+ * 此方案作为兼容方式。v0.3.4 将使用Element.animate 接口实现动画。
271
272
  */
272
273
  function highlightCellsInCssKeyFrame(cellEl: HTMLElement, rowKeyValue: UniqKey, className: string, duration: number) {
273
274
  if (cellEl.classList.contains(className)) {
@@ -146,13 +146,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
146
146
  if (!virtual_on.value) return;
147
147
  const { offsetHeight, scrollTop } = tableContainerRef.value || {};
148
148
  const { rowHeight } = virtualScroll.value;
149
- let containerHeight: number;
150
- // FIXME: 可能多次获取offsetHeight 会导致浏览器频繁重排
151
- if (typeof height === 'number') {
152
- containerHeight = height;
153
- } else {
154
- containerHeight = offsetHeight || DEFAULT_TABLE_HEIGHT;
155
- }
149
+ const containerHeight = height ?? (offsetHeight || DEFAULT_TABLE_HEIGHT);
156
150
  const { headless, headerRowHeight } = props;
157
151
  let pageSize = Math.ceil(containerHeight / rowHeight);
158
152
  if (!headless) {
@@ -191,25 +185,19 @@ export function useVirtualScroll<DT extends Record<string, any>>({
191
185
  if (!virtual_on.value) return;
192
186
 
193
187
  let startIndex = Math.floor(sTop / rowHeight);
194
- if (props.stripe) {
195
- startIndex -= 1; //预渲染1行
196
- }
197
188
  if (startIndex < 0) {
198
189
  startIndex = 0;
199
190
  }
200
191
  if (props.stripe && startIndex !== 0) {
201
192
  const scrollRows = Math.abs(oldStartIndex - startIndex);
202
193
  // 斑马纹情况下,每滚动偶数行才加载。防止斑马纹错位。
203
- if (scrollRows < 2) {
204
- return;
205
- } else if (scrollRows % 2) {
194
+ if (scrollRows % 2) {
206
195
  startIndex -= 1; // 奇数-1变成偶数
207
196
  }
208
197
  }
209
198
  let endIndex = startIndex + pageSize;
210
199
  if (props.stripe) {
211
- // 由于stripe上方预渲染-1行,这里也要预渲染1+1行
212
- endIndex += 1;
200
+ endIndex += 1; // 斑马纹下多渲染一些
213
201
  }
214
202
  const offsetTop = startIndex * rowHeight; // startIndex之前的高度
215
203
  endIndex = Math.min(endIndex, dataSourceCopy.value.length); // 溢出index修正
@@ -241,17 +229,22 @@ export function useVirtualScroll<DT extends Record<string, any>>({
241
229
  function updateVirtualScrollX(sLeft = 0) {
242
230
  if (!props.virtualX) return;
243
231
  const headerLength = tableHeaderLast.value?.length;
244
- const { scrollLeft } = virtualScrollX.value;
245
232
  if (!headerLength) return;
233
+
234
+ const { scrollLeft } = virtualScrollX.value;
246
235
  let startIndex = 0;
247
236
  let offsetLeft = 0;
248
-
237
+ /** 列宽累加 */
249
238
  let colWidthSum = 0;
239
+ /** 固定左侧列宽 */
250
240
  let leftColWidthSum = 0;
241
+ /** 横向滚动时,第一列的剩余宽度 */
242
+ let leftFirstColRestWidth = 0;
243
+
251
244
  for (let colIndex = 0; colIndex < headerLength; colIndex++) {
252
- startIndex++;
253
245
  const col = tableHeaderLast.value[colIndex];
254
246
  const colWidth = getCalculatedColWidth(col);
247
+ startIndex++;
255
248
  // fixed left 不进入计算列宽
256
249
  if (col.fixed === 'left') {
257
250
  leftColWidthSum += colWidth;
@@ -262,11 +255,12 @@ export function useVirtualScroll<DT extends Record<string, any>>({
262
255
  if (colWidthSum >= sLeft) {
263
256
  offsetLeft = colWidthSum - colWidth;
264
257
  startIndex--;
258
+ leftFirstColRestWidth = colWidthSum - sLeft;
265
259
  break;
266
260
  }
267
261
  }
268
262
  // -----
269
- colWidthSum = 0;
263
+ colWidthSum = leftFirstColRestWidth;
270
264
  const containerWidth = virtualScrollX.value.containerWidth - leftColWidthSum;
271
265
  let endIndex = headerLength;
272
266
  for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {