stk-table-vue 0.6.4 → 0.6.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/README.md CHANGED
@@ -1,9 +1,17 @@
1
1
  # StkTable (Sticky Table)
2
+ ![NPM License](https://img.shields.io/npm/l/stk-table-vue)
3
+ ![NPM Version](https://img.shields.io/npm/v/stk-table-vue)
4
+ ![NPM Type Definitions](https://img.shields.io/npm/types/stk-table-vue)
5
+ ![NPM Downloads](https://img.shields.io/npm/dw/stk-table-vue)
2
6
 
3
7
  Vue3 简易虚拟滚动表格。用于实时数据展示,新数据行高亮渐暗动效。
4
8
 
5
9
  Vue2.7支持引入源码(**ts**)使用。
6
10
 
11
+ [Stk Table Vue 文档](https://ja-plus.github.io/stk-table-vue/)
12
+
13
+ ## License
14
+ MIT
7
15
  repo:
8
16
  - [Github](https://github.com/ja-plus/stk-table-vue)
9
17
  - [Gitee](https://gitee.com/japlus/stk-table-vue) 🇨🇳
@@ -227,7 +235,7 @@ export type StkProps = {
227
235
  * 列宽拖动时,每一列都必须要有width,且minWidth/maxWidth不生效。table width会变为"fit-content"。
228
236
  * - 会自动更新props.columns中的with属性
229
237
  */
230
- colResizable?: boolean;
238
+ colResizable?: boolean | ColResizableConfig;
231
239
  /** 可拖动至最小的列宽 */
232
240
  colMinWidth?: number;
233
241
  /**
@@ -281,7 +289,7 @@ export type StkProps = {
281
289
  expandConfig?: {
282
290
  height?: number;
283
291
  };
284
- /** 列拖动配置 */
292
+ /** 行拖动配置 */
285
293
  dragRowConfig?: {
286
294
  mode?: 'none' | 'insert' | 'swap';
287
295
  };
@@ -1,4 +1,4 @@
1
- import { AutoRowHeightConfig, DragRowConfig, ExpandConfig, HeaderDragConfig, HighlightConfig, Order, PrivateRowDT, SeqConfig, SortConfig, SortOption, StkTableColumn, UniqKeyProp } from './types/index';
1
+ import { AutoRowHeightConfig, DragRowConfig, ExpandConfig, HeaderDragConfig, HighlightConfig, Order, PrivateRowDT, SeqConfig, SortConfig, SortOption, StkTableColumn, UniqKeyProp, ColResizableConfig } from './types/index';
2
2
  /** Generic stands for DataType */
3
3
  type DT = any & PrivateRowDT;
4
4
  /**
@@ -138,7 +138,7 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<{
138
138
  * 列宽拖动时,每一列都必须要有width,且minWidth/maxWidth不生效。table width会变为"fit-content"。
139
139
  * - 会自动更新props.columns中的with属性
140
140
  */
141
- colResizable?: boolean | undefined;
141
+ colResizable?: boolean | ColResizableConfig<any> | undefined;
142
142
  /** 可拖动至最小的列宽 */
143
143
  colMinWidth?: number | undefined;
144
144
  /**
@@ -169,7 +169,7 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<{
169
169
  seqConfig?: SeqConfig | undefined;
170
170
  /** 展开行配置 */
171
171
  expandConfig?: ExpandConfig | undefined;
172
- /** 列拖动配置 */
172
+ /** 行拖动配置 */
173
173
  dragRowConfig?: DragRowConfig | undefined;
174
174
  /**
175
175
  * 固定头,固定列实现方式。(非响应式)
@@ -383,7 +383,7 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<{
383
383
  * 列宽拖动时,每一列都必须要有width,且minWidth/maxWidth不生效。table width会变为"fit-content"。
384
384
  * - 会自动更新props.columns中的with属性
385
385
  */
386
- colResizable?: boolean | undefined;
386
+ colResizable?: boolean | ColResizableConfig<any> | undefined;
387
387
  /** 可拖动至最小的列宽 */
388
388
  colMinWidth?: number | undefined;
389
389
  /**
@@ -414,7 +414,7 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<{
414
414
  seqConfig?: SeqConfig | undefined;
415
415
  /** 展开行配置 */
416
416
  expandConfig?: ExpandConfig | undefined;
417
- /** 列拖动配置 */
417
+ /** 行拖动配置 */
418
418
  dragRowConfig?: DragRowConfig | undefined;
419
419
  /**
420
420
  * 固定头,固定列实现方式。(非响应式)
@@ -471,7 +471,7 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<{
471
471
  selectedCellRevokable: boolean;
472
472
  headerDrag: HeaderDragConfig;
473
473
  rowClassName: (row: any, i: number) => string;
474
- colResizable: boolean;
474
+ colResizable: boolean | ColResizableConfig<any>;
475
475
  colMinWidth: number;
476
476
  bordered: boolean | "h" | "v" | "body-v";
477
477
  autoResize: boolean | (() => void);
@@ -185,6 +185,7 @@ export type SeqConfig = {
185
185
  };
186
186
  /** Configuration options for the expand column */
187
187
  export type ExpandConfig = {
188
+ /** worked in virtual mode */
188
189
  height?: number;
189
190
  };
190
191
  export type ExpandedRow = PrivateRowDT & {
@@ -211,4 +212,7 @@ export type AutoRowHeightConfig<DT> = {
211
212
  /** Estimated row height */
212
213
  expectedHeight?: number | ((row: DT, index: number) => number);
213
214
  };
215
+ export type ColResizableConfig<DT extends Record<string, any>> = {
216
+ disabled: (col: StkTableColumn<DT>) => boolean;
217
+ };
214
218
  export {};
@@ -11,6 +11,7 @@ type Params<DT extends Record<string, any>> = {
11
11
  };
12
12
  /** 列宽拖动 */
13
13
  export declare function useColResize<DT extends Record<string, any>>({ tableContainerRef, tableHeaderLast, colResizeIndicatorRef, props, emits, colKeyGen, fixedCols, }: Params<DT>): {
14
+ colResizeOn: ComputedRef<((col: StkTableColumn<DT>) => boolean) | (() => any)>;
14
15
  isColResizing: Ref<boolean, boolean>;
15
16
  onThResizeMouseDown: (e: MouseEvent, col: StkTableColumn<DT>, leftHandle?: boolean) => void;
16
17
  };
@@ -6,14 +6,14 @@ type Params<T extends Record<string, any>> = {
6
6
  colKeyGen: ComputedRef<(col: StkTableColumn<T>) => UniqKey>;
7
7
  getFixedColPosition: ComputedRef<(col: StkTableColumn<T>) => number>;
8
8
  tableHeaders: ShallowRef<StkTableColumn<T>[][]>;
9
- tableHeaderLast: ShallowRef<StkTableColumn<T>[]>;
9
+ tableHeadersForCalc: ShallowRef<StkTableColumn<T>[][]>;
10
10
  tableContainerRef: Ref<HTMLDivElement | undefined>;
11
11
  };
12
12
  /**
13
13
  * 固定列处理
14
14
  * @returns
15
15
  */
16
- export declare function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen, getFixedColPosition, tableHeaders, tableHeaderLast, tableContainerRef, }: Params<DT>): {
16
+ export declare function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen, getFixedColPosition, tableHeaders, tableHeadersForCalc, tableContainerRef, }: Params<DT>): {
17
17
  /** 正在被固定的列 */
18
18
  fixedCols: ShallowRef<StkTableColumn<DT>[], StkTableColumn<DT>[]>;
19
19
  /** 固定列class */
@@ -1,4 +1,6 @@
1
1
  import { Order, SortConfig, SortOption, SortState, StkTableColumn } from '../types';
2
+ /** 是否空值 */
3
+ export declare function isEmptyValue(val: any, isNumber?: boolean): boolean;
2
4
  /**
3
5
  * 对有序数组插入新数据
4
6
  *
@@ -37,5 +39,5 @@ export declare function tableSort<T extends Record<string, any>>(sortOption: Sor
37
39
  /** 多级表头深度 从0开始为一级*/
38
40
  export declare function howDeepTheHeader(arr: StkTableColumn<any>[], level?: number): number;
39
41
  /** number width +px */
40
- export declare function transformWidthToStr(width?: string | number): string;
42
+ export declare function transformWidthToStr(width?: string | number): string | undefined;
41
43
  export declare function getBrowsersVersion(browserName: string): number;
@@ -1,4 +1,4 @@
1
- import { openBlock, createElementBlock, createElementVNode, watch, onMounted, onBeforeUnmount, ref, shallowRef, computed, defineComponent, nextTick, toRaw, normalizeClass, unref, normalizeStyle, createCommentVNode, Fragment, renderList, createBlock, resolveDynamicComponent, toDisplayString, renderSlot, createVNode, createTextVNode } from "vue";
1
+ import { openBlock, createElementBlock, createElementVNode, watch, onMounted, onBeforeUnmount, ref, computed, shallowRef, defineComponent, nextTick, toRaw, normalizeClass, unref, normalizeStyle, createCommentVNode, Fragment, renderList, createBlock, resolveDynamicComponent, toDisplayString, renderSlot, createVNode, createTextVNode } from "vue";
2
2
  import { interpolateRgb } from "d3-interpolate";
3
3
  const _export_sfc = (sfc, props) => {
4
4
  const target = sfc.__vccOpts || sfc;
@@ -48,7 +48,7 @@ function _sfc_render(_ctx, _cache) {
48
48
  }
49
49
  const SortIcon = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render]]);
50
50
  function isEmptyValue(val, isNumber) {
51
- let isEmpty = val === null || val === "" || val === void 0;
51
+ let isEmpty = val === null || val === void 0;
52
52
  if (isNumber) {
53
53
  isEmpty = isEmpty || typeof val === "boolean" || Number.isNaN(+val);
54
54
  }
@@ -158,6 +158,7 @@ function howDeepTheHeader(arr, level = 0) {
158
158
  return Math.max(...levels);
159
159
  }
160
160
  function transformWidthToStr(width) {
161
+ if (width === void 0) return;
161
162
  const numberWidth = Number(width);
162
163
  return width + (!Number.isNaN(numberWidth) ? "px" : "");
163
164
  }
@@ -303,6 +304,12 @@ function useColResize({
303
304
  startOffsetTableX: 0,
304
305
  revertMoveX: false
305
306
  };
307
+ const colResizeOn = computed(() => {
308
+ if (Object.prototype.toString.call(props.colResizable) === "[object Object]") {
309
+ return (col) => !props.colResizable.disabled(col);
310
+ }
311
+ return () => props.colResizable;
312
+ });
306
313
  onMounted(() => {
307
314
  initColResizeEvent();
308
315
  });
@@ -411,6 +418,7 @@ function useColResize({
411
418
  return column;
412
419
  }
413
420
  return {
421
+ colResizeOn,
414
422
  isColResizing,
415
423
  onThResizeMouseDown
416
424
  };
@@ -420,7 +428,7 @@ function useFixedCol({
420
428
  colKeyGen,
421
429
  getFixedColPosition,
422
430
  tableHeaders,
423
- tableHeaderLast,
431
+ tableHeadersForCalc,
424
432
  tableContainerRef
425
433
  }) {
426
434
  const fixedShadowCols = shallowRef([]);
@@ -443,23 +451,8 @@ function useFixedCol({
443
451
  });
444
452
  return colMap;
445
453
  });
446
- function getColAndParentCols(col, type = 1) {
447
- if (!col) return [];
448
- const colsTemp = [];
449
- let node = { __PARENT__: col };
450
- while (node = node.__PARENT__) {
451
- if (type === 1 && node.fixed) {
452
- colsTemp.push(node);
453
- }
454
- if (type === 2) {
455
- colsTemp.push(node);
456
- }
457
- }
458
- return colsTemp;
459
- }
460
454
  function updateFixedShadow(virtualScrollX) {
461
455
  const fixedColsTemp = [];
462
- const fixedShadowColsTemp = [];
463
456
  let clientWidth, scrollLeft;
464
457
  if (virtualScrollX == null ? void 0 : virtualScrollX.value) {
465
458
  const {
@@ -478,26 +471,29 @@ function useFixedCol({
478
471
  clientWidth = cw;
479
472
  scrollLeft = sl;
480
473
  }
481
- let leftShadowCol = null;
482
- let rightShadowCol = null;
483
- let left = 0;
484
- tableHeaderLast.value.forEach((col) => {
485
- const position = getFixedColPosition.value(col);
486
- if (col.fixed === "left" && position + scrollLeft > left) {
487
- leftShadowCol = col;
488
- fixedColsTemp.push(...getColAndParentCols(col, 2));
489
- }
490
- left += getCalculatedColWidth(col);
491
- if (!rightShadowCol && col.fixed === "right" && scrollLeft + clientWidth - left < position) {
492
- rightShadowCol = col;
493
- }
494
- if (rightShadowCol && col.fixed === "right") {
495
- fixedColsTemp.push(...getColAndParentCols(col, 2));
496
- }
474
+ const leftShadowCol = [];
475
+ const rightShadowCol = [];
476
+ tableHeadersForCalc.value.forEach((row, level) => {
477
+ let left = 0;
478
+ row.forEach((col) => {
479
+ const position = getFixedColPosition.value(col);
480
+ const isFixedLeft = col.fixed === "left";
481
+ const isFixedRight = col.fixed === "right";
482
+ if (isFixedLeft && position + scrollLeft > left) {
483
+ fixedColsTemp.push(col);
484
+ leftShadowCol[level] = col;
485
+ }
486
+ left += getCalculatedColWidth(col);
487
+ if (isFixedRight && scrollLeft + clientWidth - left < position) {
488
+ fixedColsTemp.push(col);
489
+ if (!rightShadowCol[level]) {
490
+ rightShadowCol[level] = col;
491
+ }
492
+ }
493
+ });
497
494
  });
498
495
  if (props.fixedColShadow) {
499
- fixedShadowColsTemp.push(...getColAndParentCols(leftShadowCol), ...getColAndParentCols(rightShadowCol));
500
- fixedShadowCols.value = fixedShadowColsTemp.filter(Boolean);
496
+ fixedShadowCols.value = [...leftShadowCol, ...rightShadowCol].filter(Boolean);
501
497
  }
502
498
  fixedCols.value = fixedColsTemp;
503
499
  }
@@ -633,7 +629,7 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
633
629
  const { ts, duration } = store;
634
630
  const timeOffset = nowTs - ts;
635
631
  if (nowTs - ts < duration) {
636
- updateRowBgc(rowKeyValue, store, timeOffset);
632
+ updateRowAnimation(rowKeyValue, store, timeOffset);
637
633
  } else {
638
634
  highlightDimRowsAnimation.delete(rowKeyValue);
639
635
  }
@@ -708,7 +704,7 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
708
704
  const rowKeyValue = rowKeyValues[i];
709
705
  const store = { ts: nowTs, visible: false, keyframe, duration };
710
706
  highlightDimRowsAnimation.set(rowKeyValue, store);
711
- updateRowBgc(rowKeyValue, store, 0);
707
+ updateRowAnimation(rowKeyValue, store, 0);
712
708
  }
713
709
  calcRowHighlightLoop();
714
710
  } else {
@@ -770,7 +766,7 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
770
766
  }, duration)
771
767
  );
772
768
  }
773
- function updateRowBgc(rowKeyValue, store, timeOffset) {
769
+ function updateRowAnimation(rowKeyValue, store, timeOffset) {
774
770
  const rowEl = document.getElementById(stkTableId + "-" + String(rowKeyValue));
775
771
  const { visible, keyframe, duration: initialDuration } = store;
776
772
  if (!rowEl) {
@@ -916,7 +912,7 @@ function useThDrag({ props, emits, colKeyGen }) {
916
912
  emits("th-drop", th.dataset.colKey);
917
913
  }
918
914
  function handleColOrderChange(dragStartKey, dragEndKey) {
919
- if (!dragStartKey || !dragEndKey) return;
915
+ if (isEmptyValue(dragStartKey) || isEmptyValue(dragEndKey)) return;
920
916
  if (dragConfig.value.mode !== "none") {
921
917
  const columns = [...props.columns];
922
918
  const dragStartIndex = columns.findIndex((col) => colKeyGen.value(col) === dragStartKey);
@@ -1064,6 +1060,9 @@ function useVirtualScroll({
1064
1060
  offsetLeft: 0,
1065
1061
  scrollLeft: 0
1066
1062
  });
1063
+ const hasExpandCol = computed(() => {
1064
+ return tableHeaderLast.value.some((col) => col.type === "expand");
1065
+ });
1067
1066
  const virtual_on = computed(() => {
1068
1067
  return props.virtual && dataSourceCopy.value.length > virtualScroll.value.pageSize * 2;
1069
1068
  });
@@ -1170,7 +1169,8 @@ function useVirtualScroll({
1170
1169
  let expectedHeight;
1171
1170
  if (storedHeight) {
1172
1171
  return storedHeight;
1173
- } else if (expectedHeight = (_a = props.autoRowHeight) == null ? void 0 : _a.expectedHeight) {
1172
+ }
1173
+ if (expectedHeight = (_a = props.autoRowHeight) == null ? void 0 : _a.expectedHeight) {
1174
1174
  if (typeof expectedHeight === "function") {
1175
1175
  return expectedHeight(row);
1176
1176
  } else {
@@ -1179,6 +1179,18 @@ function useVirtualScroll({
1179
1179
  }
1180
1180
  return props.rowHeight || DEFAULT_ROW_HEIGHT;
1181
1181
  };
1182
+ const createGetRowHeightFn = () => {
1183
+ var _a;
1184
+ if (props.autoRowHeight) {
1185
+ return (row) => getAutoRowHeight(row);
1186
+ }
1187
+ if (hasExpandCol.value) {
1188
+ const { rowHeight } = virtualScroll.value;
1189
+ const expandedRowHeight = ((_a = props.expandConfig) == null ? void 0 : _a.height) || rowHeight;
1190
+ return (row) => row.__EXPANDED_ROW__ ? expandedRowHeight : rowHeight;
1191
+ }
1192
+ return () => props.rowHeight || DEFAULT_ROW_HEIGHT;
1193
+ };
1182
1194
  function updateVirtualScrollY(sTop = 0) {
1183
1195
  var _a;
1184
1196
  const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex, endIndex: oldEndIndex } = virtualScroll.value;
@@ -1186,21 +1198,27 @@ function useVirtualScroll({
1186
1198
  if (!virtual_on.value) {
1187
1199
  return;
1188
1200
  }
1201
+ const dataSourceCopyTemp = dataSourceCopy.value;
1189
1202
  const { autoRowHeight, stripe, optimizeVue2Scroll } = props;
1190
1203
  let startIndex = 0;
1191
1204
  let autoRowHeightTop = 0;
1192
- if (autoRowHeight) {
1193
- (_a = trRef.value) == null ? void 0 : _a.forEach((tr) => {
1194
- const { rowKey } = tr.dataset;
1195
- if (!rowKey || autoRowHeightMap.has(rowKey)) return;
1196
- autoRowHeightMap.set(rowKey, tr.offsetHeight);
1197
- });
1198
- for (let i = 0; i < dataSourceCopy.value.length; i++) {
1199
- const height = getAutoRowHeight(dataSourceCopy.value[i]);
1205
+ let getRowHeight = null;
1206
+ const dataLength = dataSourceCopyTemp.length;
1207
+ if (autoRowHeight || hasExpandCol.value) {
1208
+ if (autoRowHeight) {
1209
+ (_a = trRef.value) == null ? void 0 : _a.forEach((tr) => {
1210
+ const { rowKey } = tr.dataset;
1211
+ if (!rowKey || autoRowHeightMap.has(rowKey)) return;
1212
+ autoRowHeightMap.set(rowKey, tr.offsetHeight);
1213
+ });
1214
+ }
1215
+ getRowHeight = createGetRowHeightFn();
1216
+ for (let i = 0; i < dataLength; i++) {
1217
+ const height = getRowHeight(dataSourceCopyTemp[i]);
1200
1218
  autoRowHeightTop += height;
1201
1219
  if (autoRowHeightTop >= sTop) {
1202
1220
  startIndex = i;
1203
- autoRowHeightTop = autoRowHeightTop - height;
1221
+ autoRowHeightTop -= height;
1204
1222
  break;
1205
1223
  }
1206
1224
  }
@@ -1210,13 +1228,13 @@ function useVirtualScroll({
1210
1228
  let endIndex = startIndex + pageSize;
1211
1229
  if (stripe && startIndex > 0 && startIndex % 2) {
1212
1230
  startIndex -= 1;
1213
- if (autoRowHeight) {
1214
- const height = getAutoRowHeight(dataSourceCopy.value[startIndex]);
1231
+ if (autoRowHeight || hasExpandCol.value) {
1232
+ const height = getRowHeight(dataSourceCopyTemp[startIndex]);
1215
1233
  autoRowHeightTop -= height;
1216
1234
  }
1217
1235
  }
1218
1236
  startIndex = Math.max(0, startIndex);
1219
- endIndex = Math.min(endIndex, dataSourceCopy.value.length);
1237
+ endIndex = Math.min(endIndex, dataLength);
1220
1238
  if (startIndex >= endIndex) {
1221
1239
  startIndex = endIndex - pageSize;
1222
1240
  }
@@ -1224,7 +1242,7 @@ function useVirtualScroll({
1224
1242
  window.clearTimeout(vue2ScrollYTimeout);
1225
1243
  }
1226
1244
  let offsetTop = 0;
1227
- if (autoRowHeight) {
1245
+ if (autoRowHeight || hasExpandCol.value) {
1228
1246
  offsetTop = autoRowHeightTop;
1229
1247
  } else {
1230
1248
  if (oldStartIndex === startIndex && oldEndIndex === endIndex) {
@@ -1473,9 +1491,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1473
1491
  getFixedColPosition,
1474
1492
  tableContainerRef,
1475
1493
  tableHeaders,
1476
- tableHeaderLast
1494
+ tableHeadersForCalc
1477
1495
  });
1478
- const { isColResizing, onThResizeMouseDown } = useColResize({
1496
+ const { isColResizing, onThResizeMouseDown, colResizeOn } = useColResize({
1479
1497
  props,
1480
1498
  emits,
1481
1499
  colKeyGen,
@@ -2175,12 +2193,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2175
2193
  col.sorter ? (openBlock(), createElementBlock("span", _hoisted_4, [
2176
2194
  createVNode(SortIcon)
2177
2195
  ])) : createCommentVNode("", true),
2178
- _ctx.colResizable && colIndex > 0 ? (openBlock(), createElementBlock("div", {
2196
+ unref(colResizeOn)(col) && colIndex > 0 ? (openBlock(), createElementBlock("div", {
2179
2197
  key: 4,
2180
2198
  class: "table-header-resizer left",
2181
2199
  onMousedown: (e) => unref(onThResizeMouseDown)(e, col, true)
2182
2200
  }, null, 40, _hoisted_5)) : createCommentVNode("", true),
2183
- _ctx.colResizable ? (openBlock(), createElementBlock("div", {
2201
+ unref(colResizeOn)(col) ? (openBlock(), createElementBlock("div", {
2184
2202
  key: 5,
2185
2203
  class: "table-header-resizer right",
2186
2204
  onMousedown: (e) => unref(onThResizeMouseDown)(e, col)
@@ -2235,7 +2253,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2235
2253
  "expanded-row": row && row.__EXPANDED_ROW__
2236
2254
  }),
2237
2255
  style: normalizeStyle({
2238
- "--row-height": row && row.__EXPANDED_ROW__ && unref(virtual_on) && ((_a = props.expandConfig) == null ? void 0 : _a.height) && ((_b = props.expandConfig) == null ? void 0 : _b.height) + "px"
2256
+ "--row-height": row && row.__EXPANDED_ROW__ && props.virtual && ((_a = props.expandConfig) == null ? void 0 : _a.height) && ((_b = props.expandConfig) == null ? void 0 : _b.height) + "px"
2239
2257
  }),
2240
2258
  onClick: (e) => onRowClick(e, row),
2241
2259
  onDblclick: (e) => onRowDblclick(e, row),
package/lib/style.css CHANGED
@@ -38,8 +38,6 @@
38
38
  display:flex;
39
39
  flex-direction:column;
40
40
  box-sizing:border-box;
41
- background-image:linear-gradient(180deg, #e8e8f4 1px, transparent 1px), linear-gradient(270deg, #e8e8f4 1px, transparent 1px), linear-gradient(0deg, #e8e8f4 1px, transparent 1px);
42
- background-image:var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
43
41
  }
44
42
  .stk-table.dark{
45
43
  --th-bgc:#202029;
@@ -63,21 +61,22 @@
63
61
  --drag-handle-hover-color:#5d6064;
64
62
  color:#d1d1e0;
65
63
  }
66
- .stk-table.headless{
64
+ .stk-table.headless.border{
67
65
  border-top:1px solid var(--border-color);
68
66
  background-image:var(--bg-border-right), var(--bg-border-bottom);
69
67
  }
70
68
  .stk-table.col-resizable .stk-table-main{
71
- width:-moz-fit-content !important;
72
- width:fit-content !important;
73
- min-width:-moz-min-content !important;
74
- min-width:min-content !important;
69
+ width:-moz-fit-content;
70
+ width:fit-content;
71
+ min-width:-moz-min-content;
72
+ min-width:min-content;
75
73
  }
76
74
  .stk-table.is-col-resizing th{
77
75
  pointer-events:none;
78
76
  }
79
77
  .stk-table.border{
80
78
  border-left:1px solid var(--border-color);
79
+ background-image:var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
81
80
  }
82
81
  .stk-table.border th,
83
82
  .stk-table.border td{
@@ -104,13 +103,13 @@
104
103
  .stk-table.stripe.vt-on .stk-tbody-main tr:nth-child(odd){
105
104
  background-color:var(--stripe-bgc);
106
105
  }
107
- .stk-table.stripe.row-hover .stk-tbody-main tr:hover{
106
+ .stk-table.stripe.row-hover .stk-table-main .stk-tbody-main tr:hover{
108
107
  background-color:var(--tr-hover-bgc);
109
108
  }
110
- .stk-table.stripe.row-active .stk-tbody-main tr.active{
109
+ .stk-table.stripe.row-active .stk-table-main .stk-tbody-main tr.active{
111
110
  background-color:var(--tr-active-bgc);
112
111
  }
113
- .stk-table.row-hover .stk-tbody-main tr:hover{
112
+ .stk-table.row-hover .stk-table-main .stk-tbody-main tr:hover{
114
113
  background-color:var(--tr-hover-bgc);
115
114
  }
116
115
  .stk-table.row-active .stk-tbody-main tr.active{
@@ -142,6 +141,9 @@
142
141
  max-height:calc(var(--header-row-height) * 1);
143
142
  max-height:calc(var(--header-row-height) * var(--row-span, 1));
144
143
  }
144
+ .stk-table.virtual .table-header-cell-wrapper .table-header-title{
145
+ max-height:inherit;
146
+ }
145
147
  .stk-table.virtual tbody td{
146
148
  height:var(--row-height);
147
149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stk-table-vue",
3
- "version": "0.6.4",
3
+ "version": "0.6.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",
@@ -13,9 +13,10 @@
13
13
  "dev": "vite",
14
14
  "build": "vite build",
15
15
  "test": "vitest",
16
- "docs:dev": "vitepress dev docs",
17
- "docs:build": "vitepress build docs",
18
- "docs:preview": "vitepress preview docs"
16
+ "docs:dev": "vitepress dev docs-src",
17
+ "docs:build": "vitepress build docs-src",
18
+ "docs:preview": "vitepress preview docs-src",
19
+ "docs:update": "cp -rf ./docs-src/.vitepress/dist/* ./docs"
19
20
  },
20
21
  "keywords": [
21
22
  "virtual table",
@@ -40,6 +41,7 @@
40
41
  "license": "MIT",
41
42
  "devDependencies": {
42
43
  "@types/d3-interpolate": "^3.0.4",
44
+ "@types/mockjs": "^1.0.10",
43
45
  "@types/node": "^20.12.10",
44
46
  "@typescript-eslint/eslint-plugin": "^7.7.0",
45
47
  "@typescript-eslint/parser": "^7.7.0",
@@ -52,6 +54,8 @@
52
54
  "eslint-plugin-vue": "^9.25.0",
53
55
  "happy-dom": "^12.10.3",
54
56
  "less": "^4.2.0",
57
+ "mitt": "^3.0.1",
58
+ "mockjs": "^1.1.0",
55
59
  "postcss": "^8.4.47",
56
60
  "postcss-discard-comments": "^6.0.2",
57
61
  "postcss-preset-env": "^9.5.11",
@@ -60,7 +64,7 @@
60
64
  "vite": "^5.4.10",
61
65
  "vite-plugin-dts": "^4.3.0",
62
66
  "vitepress": "^1.5.0",
63
- "vitepress-demo-plugin": "^1.1.1",
67
+ "vitepress-demo-plugin": "^1.2.2",
64
68
  "vitest": "^2.1.3",
65
69
  "vue": "^3.5.12",
66
70
  "vue-eslint-parser": "^9.4.2"
@@ -102,11 +102,11 @@
102
102
  </span>
103
103
  <!-- 列宽拖动handler -->
104
104
  <div
105
- v-if="colResizable && colIndex > 0"
105
+ v-if="colResizeOn(col) && colIndex > 0"
106
106
  class="table-header-resizer left"
107
107
  @mousedown="e => onThResizeMouseDown(e, col, true)"
108
108
  ></div>
109
- <div v-if="colResizable" class="table-header-resizer right" @mousedown="e => onThResizeMouseDown(e, col)"></div>
109
+ <div v-if="colResizeOn(col)" class="table-header-resizer right" @mousedown="e => onThResizeMouseDown(e, col)"></div>
110
110
  </div>
111
111
  </th>
112
112
  <!-- 这个th用于横向虚拟滚动表格右边距 width、maxWidth 用于兼容低版本浏览器-->
@@ -139,7 +139,8 @@
139
139
  'expanded-row': row && row.__EXPANDED_ROW__,
140
140
  }"
141
141
  :style="{
142
- '--row-height': row && row.__EXPANDED_ROW__ && virtual_on && props.expandConfig?.height && props.expandConfig?.height + 'px',
142
+ '--row-height':
143
+ row && row.__EXPANDED_ROW__ && props.virtual && props.expandConfig?.height && props.expandConfig?.height + 'px',
143
144
  }"
144
145
  @click="e => onRowClick(e, row)"
145
146
  @dblclick="e => onRowDblclick(e, row)"
@@ -253,6 +254,7 @@ import {
253
254
  StkTableColumn,
254
255
  TagType,
255
256
  UniqKeyProp,
257
+ ColResizableConfig,
256
258
  } from './types/index';
257
259
  import { useAutoResize } from './useAutoResize';
258
260
  import { useColResize } from './useColResize';
@@ -354,7 +356,7 @@ const props = withDefaults(
354
356
  * 列宽拖动时,每一列都必须要有width,且minWidth/maxWidth不生效。table width会变为"fit-content"。
355
357
  * - 会自动更新props.columns中的with属性
356
358
  */
357
- colResizable?: boolean;
359
+ colResizable?: boolean | ColResizableConfig<DT>;
358
360
  /** 可拖动至最小的列宽 */
359
361
  colMinWidth?: number;
360
362
  /**
@@ -385,7 +387,7 @@ const props = withDefaults(
385
387
  seqConfig?: SeqConfig;
386
388
  /** 展开行配置 */
387
389
  expandConfig?: ExpandConfig;
388
- /** 列拖动配置 */
390
+ /** 行拖动配置 */
389
391
  dragRowConfig?: DragRowConfig;
390
392
  /**
391
393
  * 固定头,固定列实现方式。(非响应式)
@@ -747,10 +749,10 @@ const { fixedCols, fixedColClassMap, updateFixedShadow } = useFixedCol({
747
749
  getFixedColPosition,
748
750
  tableContainerRef,
749
751
  tableHeaders,
750
- tableHeaderLast,
752
+ tableHeadersForCalc,
751
753
  });
752
754
 
753
- const { isColResizing, onThResizeMouseDown } = useColResize({
755
+ const { isColResizing, onThResizeMouseDown, colResizeOn } = useColResize({
754
756
  props,
755
757
  emits,
756
758
  colKeyGen,
@@ -50,9 +50,6 @@
50
50
  flex-direction: column;
51
51
  box-sizing: border-box;
52
52
 
53
- /* 下面border用于表格内容不满高度时,绘制表格边界线 */
54
- background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
55
-
56
53
  /**深色模式 */
57
54
  &.dark {
58
55
  --th-bgc: #202029;
@@ -85,17 +82,20 @@
85
82
  /* ⭐这里加background-color会导致表格出滚动白屏*/
86
83
  color: #d1d1e0;
87
84
  }
85
+
88
86
 
89
87
  &.headless {
90
- border-top: 1px solid var(--border-color);
91
- background-image: var(--bg-border-right), var(--bg-border-bottom);
88
+ &.border {
89
+ border-top: 1px solid var(--border-color);
90
+ background-image: var(--bg-border-right), var(--bg-border-bottom);
91
+ }
92
92
  }
93
93
 
94
94
  /* 调整列宽的话,表格宽度应当自适应 */
95
95
  &.col-resizable {
96
96
  .stk-table-main {
97
- width: fit-content !important;
98
- min-width: min-content !important;
97
+ width: fit-content;
98
+ min-width: min-content;
99
99
  }
100
100
  }
101
101
 
@@ -115,6 +115,8 @@
115
115
  * - sticky 定位方案需要占用位置。高度为0。
116
116
  */
117
117
  border-left: 1px solid var(--border-color);
118
+ /* 下面border用于表格内容不满高度时,绘制表格边界线 */
119
+ background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
118
120
 
119
121
  th,
120
122
  td {
@@ -155,17 +157,18 @@
155
157
  background-color: var(--stripe-bgc);
156
158
  }
157
159
 
158
- &.row-hover .stk-tbody-main tr:hover {
160
+ &.row-hover .stk-table-main .stk-tbody-main tr:hover {
159
161
  background-color: var(--tr-hover-bgc);
160
162
  }
161
163
 
162
- &.row-active .stk-tbody-main tr.active {
164
+ &.row-active .stk-table-main .stk-tbody-main tr.active {
163
165
  background-color: var(--tr-active-bgc);
164
166
  }
165
167
  }
166
168
 
167
169
 
168
- &.row-hover .stk-tbody-main tr:hover {
170
+ /** more weight for custom row background*/
171
+ &.row-hover .stk-table-main .stk-tbody-main tr:hover {
169
172
  background-color: var(--tr-hover-bgc);
170
173
  }
171
174
 
@@ -213,6 +216,10 @@
213
216
  .table-header-cell-wrapper {
214
217
  overflow: hidden;
215
218
  max-height: calc(var(--header-row-height) * var(--row-span, 1));
219
+
220
+ .table-header-title {
221
+ max-height: inherit;
222
+ }
216
223
  }
217
224
 
218
225
  tbody td {
@@ -200,6 +200,7 @@ export type SeqConfig = {
200
200
 
201
201
  /** Configuration options for the expand column */
202
202
  export type ExpandConfig = {
203
+ /** worked in virtual mode */
203
204
  height?: number;
204
205
  };
205
206
 
@@ -232,3 +233,7 @@ export type AutoRowHeightConfig<DT> = {
232
233
  /** Estimated row height */
233
234
  expectedHeight?: number | ((row: DT, index: number) => number);
234
235
  };
236
+
237
+ export type ColResizableConfig<DT extends Record<string, any>> = {
238
+ disabled: (col: StkTableColumn<DT>) => boolean;
239
+ };
@@ -1,4 +1,4 @@
1
- import { ComputedRef, Ref, ShallowRef, onBeforeUnmount, onMounted, ref } from 'vue';
1
+ import { ComputedRef, Ref, ShallowRef, computed, onBeforeUnmount, onMounted, ref } from 'vue';
2
2
  import { StkTableColumn, UniqKey } from './types';
3
3
  import { getCalculatedColWidth } from './utils/constRefUtils';
4
4
 
@@ -47,6 +47,14 @@ export function useColResize<DT extends Record<string, any>>({
47
47
  revertMoveX: false,
48
48
  };
49
49
 
50
+ /** 是否可拖动 */
51
+ const colResizeOn = computed(() => {
52
+ if (Object.prototype.toString.call(props.colResizable) === '[object Object]') {
53
+ return (col: StkTableColumn<DT>) => !props.colResizable.disabled(col);
54
+ }
55
+ return () => props.colResizable;
56
+ });
57
+
50
58
  onMounted(() => {
51
59
  initColResizeEvent();
52
60
  });
@@ -93,7 +101,7 @@ export function useColResize<DT extends Record<string, any>>({
93
101
  // 对于固定右侧的列,拖动左侧的把,需要反向计算
94
102
  revertMoveX = true;
95
103
  } else {
96
- // 默认拖动右侧的把,取上一列
104
+ // 取上一列
97
105
  if (colIndex - 1 >= 0) {
98
106
  col = tableHeaderLastValue[colIndex - 1];
99
107
  }
@@ -198,6 +206,7 @@ export function useColResize<DT extends Record<string, any>>({
198
206
  }
199
207
 
200
208
  return {
209
+ colResizeOn,
201
210
  isColResizing,
202
211
  onThResizeMouseDown,
203
212
  };
@@ -8,7 +8,7 @@ type Params<T extends Record<string, any>> = {
8
8
  colKeyGen: ComputedRef<(col: StkTableColumn<T>) => UniqKey>;
9
9
  getFixedColPosition: ComputedRef<(col: StkTableColumn<T>) => number>;
10
10
  tableHeaders: ShallowRef<StkTableColumn<T>[][]>;
11
- tableHeaderLast: ShallowRef<StkTableColumn<T>[]>;
11
+ tableHeadersForCalc: ShallowRef<StkTableColumn<T>[][]>;
12
12
  tableContainerRef: Ref<HTMLDivElement | undefined>;
13
13
  };
14
14
 
@@ -21,7 +21,7 @@ export function useFixedCol<DT extends Record<string, any>>({
21
21
  colKeyGen,
22
22
  getFixedColPosition,
23
23
  tableHeaders,
24
- tableHeaderLast,
24
+ tableHeadersForCalc,
25
25
  tableContainerRef,
26
26
  }: Params<DT>) {
27
27
  /** 保存需要出现阴影的列 */
@@ -56,27 +56,26 @@ export function useFixedCol<DT extends Record<string, any>>({
56
56
  * @param type 1-shadow(阴影) 2-active(被固定的列)
57
57
  *
58
58
  */
59
- function getColAndParentCols(col: StkTableColumn<DT> | null, type: 1 | 2 = 1) {
60
- if (!col) return [];
61
- const colsTemp: StkTableColumn<DT>[] = [];
62
- let node: any = { __PARENT__: col };
63
- while ((node = node.__PARENT__)) {
64
- if (type === 1 && node.fixed) {
65
- // shadow
66
- colsTemp.push(node);
67
- }
68
- if (type === 2) {
69
- // active
70
- colsTemp.push(node);
71
- }
72
- }
73
- return colsTemp;
74
- }
59
+ // function getColAndParentCols(col: StkTableColumn<DT> | null, type: 1 | 2 = 1) {
60
+ // if (!col) return [];
61
+ // const colsTemp: StkTableColumn<DT>[] = [];
62
+ // let node: any = { __PARENT__: col };
63
+ // while ((node = node.__PARENT__)) {
64
+ // if (type === 1 && node.fixed) {
65
+ // // shadow
66
+ // colsTemp.push(node);
67
+ // }
68
+ // if (type === 2) {
69
+ // // active
70
+ // colsTemp.push(node);
71
+ // }
72
+ // }
73
+ // return colsTemp;
74
+ // }
75
75
 
76
76
  /** 滚动条变化时,更新需要展示阴影的列 */
77
77
  function updateFixedShadow(virtualScrollX?: Ref<VirtualScrollXStore>) {
78
78
  const fixedColsTemp: StkTableColumn<DT>[] = [];
79
- const fixedShadowColsTemp: (StkTableColumn<DT> | null)[] = [];
80
79
  let clientWidth, /* scrollWidth, */ scrollLeft;
81
80
 
82
81
  if (virtualScrollX?.value) {
@@ -95,31 +94,38 @@ export function useFixedCol<DT extends Record<string, any>>({
95
94
  * 根据横向滚动位置,计算出哪个列需要展示阴影
96
95
  *****/
97
96
  /** 左侧需要展示阴影的列 */
98
- let leftShadowCol: StkTableColumn<DT> | null = null;
97
+ const leftShadowCol: StkTableColumn<DT>[] = [];
99
98
  /** 右侧展示阴影的列 */
100
- let rightShadowCol: StkTableColumn<DT> | null = null;
101
- let left = 0;
102
- /**
103
- * 左侧第n个fixed:left 计算要加上前面所有left 的列宽。
104
- */
105
- tableHeaderLast.value.forEach(col => {
106
- const position = getFixedColPosition.value(col);
107
- if (col.fixed === 'left' && position + scrollLeft > left) {
108
- leftShadowCol = col;
109
- fixedColsTemp.push(...getColAndParentCols(col, 2));
110
- }
111
- left += getCalculatedColWidth(col);
112
- if (!rightShadowCol && col.fixed === 'right' && scrollLeft + clientWidth - left < position) {
113
- rightShadowCol = col;
114
- }
115
- if (rightShadowCol && col.fixed === 'right') {
116
- fixedColsTemp.push(...getColAndParentCols(col, 2));
117
- }
99
+ const rightShadowCol: StkTableColumn<DT>[] = [];
100
+ tableHeadersForCalc.value.forEach((row, level) => {
101
+ /**
102
+ * 左侧第n个fixed:left 计算要加上前面所有left 的列宽。
103
+ */
104
+ let left = 0;
105
+ row.forEach(col => {
106
+ const position = getFixedColPosition.value(col);
107
+ const isFixedLeft = col.fixed === 'left';
108
+ const isFixedRight = col.fixed === 'right';
109
+
110
+ if (isFixedLeft && position + scrollLeft > left) {
111
+ fixedColsTemp.push(col);
112
+ leftShadowCol[level] = col;
113
+ }
114
+
115
+ left += getCalculatedColWidth(col);
116
+
117
+ if (isFixedRight && scrollLeft + clientWidth - left < position) {
118
+ fixedColsTemp.push(col);
119
+ // 右固定列阴影,只要第一列
120
+ if (!rightShadowCol[level]) {
121
+ rightShadowCol[level] = col;
122
+ }
123
+ }
124
+ });
118
125
  });
119
126
 
120
127
  if (props.fixedColShadow) {
121
- fixedShadowColsTemp.push(...getColAndParentCols(leftShadowCol), ...getColAndParentCols(rightShadowCol));
122
- fixedShadowCols.value = (fixedShadowColsTemp as (StkTableColumn<DT> | null)[]).filter(Boolean) as StkTableColumn<DT>[];
128
+ fixedShadowCols.value = [...leftShadowCol, ...rightShadowCol].filter(Boolean) as StkTableColumn<DT>[];
123
129
  }
124
130
 
125
131
  fixedCols.value = fixedColsTemp;
@@ -89,7 +89,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
89
89
  const { ts, duration } = store;
90
90
  const timeOffset = nowTs - ts;
91
91
  if (nowTs - ts < duration) {
92
- updateRowBgc(rowKeyValue, store, timeOffset);
92
+ updateRowAnimation(rowKeyValue, store, timeOffset);
93
93
  } else {
94
94
  highlightDimRowsAnimation.delete(rowKeyValue);
95
95
  }
@@ -197,7 +197,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
197
197
  const rowKeyValue = rowKeyValues[i];
198
198
  const store: HighlightDimRowStore = { ts: nowTs, visible: false, keyframe, duration };
199
199
  highlightDimRowsAnimation.set(rowKeyValue, store);
200
- updateRowBgc(rowKeyValue, store, 0);
200
+ updateRowAnimation(rowKeyValue, store, 0);
201
201
  }
202
202
  calcRowHighlightLoop();
203
203
  } else {
@@ -279,7 +279,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
279
279
  * @param store highlightDimRowStore 的引用对象
280
280
  * @param timeOffset 距动画开始经过的时长
281
281
  */
282
- function updateRowBgc(rowKeyValue: UniqKey, store: HighlightDimRowStore, timeOffset: number) {
282
+ function updateRowAnimation(rowKeyValue: UniqKey, store: HighlightDimRowStore, timeOffset: number) {
283
283
  const rowEl = document.getElementById(stkTableId + '-' + String(rowKeyValue));
284
284
  const { visible, keyframe, duration: initialDuration } = store;
285
285
  if (!rowEl) {
@@ -1,5 +1,6 @@
1
1
  import { computed, ComputedRef } from 'vue';
2
2
  import { StkTableColumn, UniqKey } from './types';
3
+ import { isEmptyValue } from './utils';
3
4
 
4
5
  type Params<T extends Record<string, any>> = {
5
6
  props: any;
@@ -57,7 +58,6 @@ export function useThDrag<DT extends Record<string, any>>({ props, emits, colKey
57
58
  const th = findParentTH(e);
58
59
  if (!th) return;
59
60
  const dragStartKey = e.dataTransfer?.getData('text');
60
-
61
61
  if (dragStartKey !== th.dataset.colKey) {
62
62
  handleColOrderChange(dragStartKey, th.dataset.colKey);
63
63
  }
@@ -66,7 +66,7 @@ export function useThDrag<DT extends Record<string, any>>({ props, emits, colKey
66
66
 
67
67
  /** 列拖动交换顺序 */
68
68
  function handleColOrderChange(dragStartKey: string | undefined, dragEndKey: string | undefined) {
69
- if (!dragStartKey || !dragEndKey) return;
69
+ if (isEmptyValue(dragStartKey) || isEmptyValue(dragEndKey)) return;
70
70
 
71
71
  if (dragConfig.value.mode !== 'none') {
72
72
  const columns = [...props.columns];
@@ -79,6 +79,8 @@ export function useVirtualScroll<DT extends Record<string, any>>({
79
79
  scrollHeight: 0,
80
80
  });
81
81
 
82
+ // TODO: init pageSize
83
+
82
84
  const virtualScrollX = ref<VirtualScrollXStore>({
83
85
  containerWidth: 0,
84
86
  scrollWidth: 0,
@@ -88,6 +90,10 @@ export function useVirtualScroll<DT extends Record<string, any>>({
88
90
  scrollLeft: 0,
89
91
  });
90
92
 
93
+ const hasExpandCol = computed(() => {
94
+ return tableHeaderLast.value.some(col => col.type === 'expand');
95
+ });
96
+
91
97
  /** 是否虚拟滚动标志 */
92
98
  const virtual_on = computed(() => {
93
99
  return props.virtual && dataSourceCopy.value.length > virtualScroll.value.pageSize * 2;
@@ -198,10 +204,9 @@ export function useVirtualScroll<DT extends Record<string, any>>({
198
204
  const headerToBodyRowHeightCount = Math.floor(headerHeight / rowHeight);
199
205
  pageSize -= headerToBodyRowHeightCount; //减去表头行数
200
206
  }
201
- /** 最大的scrollTop */
202
207
  const maxScrollTop = dataSourceCopy.value.length * rowHeight + tableHeaderHeight.value - containerHeight;
203
208
  if (scrollTop > maxScrollTop) {
204
- /** 用于修复: 滚动条不在顶部时,表格数据变少,导致滚动条位置有误 */
209
+ /** fix: 滚动条不在顶部时,表格数据变少,导致滚动条位置有误 */
205
210
  scrollTop = maxScrollTop;
206
211
  }
207
212
  Object.assign(virtualScroll.value, { containerHeight, pageSize, scrollHeight });
@@ -237,7 +242,8 @@ export function useVirtualScroll<DT extends Record<string, any>>({
237
242
  let expectedHeight;
238
243
  if (storedHeight) {
239
244
  return storedHeight;
240
- } else if ((expectedHeight = props.autoRowHeight?.expectedHeight)) {
245
+ }
246
+ if ((expectedHeight = props.autoRowHeight?.expectedHeight)) {
241
247
  if (typeof expectedHeight === 'function') {
242
248
  return expectedHeight(row);
243
249
  } else {
@@ -247,6 +253,18 @@ export function useVirtualScroll<DT extends Record<string, any>>({
247
253
  return props.rowHeight || DEFAULT_ROW_HEIGHT;
248
254
  };
249
255
 
256
+ const createGetRowHeightFn: () => (row: DT) => number = () => {
257
+ if (props.autoRowHeight) {
258
+ return (row: DT) => getAutoRowHeight(row);
259
+ }
260
+ if (hasExpandCol.value) {
261
+ const { rowHeight } = virtualScroll.value;
262
+ const expandedRowHeight: number = props.expandConfig?.height || rowHeight;
263
+ return (row: DT) => (row.__EXPANDED_ROW__ ? expandedRowHeight : rowHeight);
264
+ }
265
+ return () => props.rowHeight || (DEFAULT_ROW_HEIGHT as number);
266
+ };
267
+
250
268
  /** 通过滚动条位置,计算虚拟滚动的参数 */
251
269
  function updateVirtualScrollY(sTop = 0) {
252
270
  const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex, endIndex: oldEndIndex } = virtualScroll.value;
@@ -257,24 +275,32 @@ export function useVirtualScroll<DT extends Record<string, any>>({
257
275
  if (!virtual_on.value) {
258
276
  return;
259
277
  }
278
+
279
+ const dataSourceCopyTemp = dataSourceCopy.value;
260
280
  const { autoRowHeight, stripe, optimizeVue2Scroll } = props;
261
281
 
262
282
  let startIndex = 0;
263
-
264
283
  let autoRowHeightTop = 0;
265
- if (autoRowHeight) {
266
- trRef.value?.forEach(tr => {
267
- const { rowKey } = tr.dataset;
268
- if (!rowKey || autoRowHeightMap.has(rowKey)) return;
269
- autoRowHeightMap.set(rowKey, tr.offsetHeight);
270
- });
271
-
272
- for (let i = 0; i < dataSourceCopy.value.length; i++) {
273
- const height = getAutoRowHeight(dataSourceCopy.value[i]);
284
+ let getRowHeight: ReturnType<typeof createGetRowHeightFn> | null = null;
285
+ const dataLength = dataSourceCopyTemp.length;
286
+
287
+ if (autoRowHeight || hasExpandCol.value) {
288
+ if (autoRowHeight) {
289
+ trRef.value?.forEach(tr => {
290
+ const { rowKey } = tr.dataset;
291
+ if (!rowKey || autoRowHeightMap.has(rowKey)) return;
292
+ autoRowHeightMap.set(rowKey, tr.offsetHeight);
293
+ });
294
+ }
295
+
296
+ getRowHeight = createGetRowHeightFn();
297
+
298
+ for (let i = 0; i < dataLength; i++) {
299
+ const height = getRowHeight(dataSourceCopyTemp[i]);
274
300
  autoRowHeightTop += height;
275
301
  if (autoRowHeightTop >= sTop) {
276
302
  startIndex = i;
277
- autoRowHeightTop = autoRowHeightTop - height;
303
+ autoRowHeightTop -= height;
278
304
  break;
279
305
  }
280
306
  }
@@ -287,8 +313,8 @@ export function useVirtualScroll<DT extends Record<string, any>>({
287
313
  if (stripe && startIndex > 0 && startIndex % 2) {
288
314
  // 斑马纹情况下,每滚动偶数行才加载。防止斑马纹错位。
289
315
  startIndex -= 1; // 奇数-1变成偶数
290
- if (autoRowHeight) {
291
- const height = getAutoRowHeight(dataSourceCopy.value[startIndex]);
316
+ if (autoRowHeight || hasExpandCol.value) {
317
+ const height = getRowHeight!(dataSourceCopyTemp[startIndex]);
292
318
  autoRowHeightTop -= height;
293
319
  }
294
320
  }
@@ -296,7 +322,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
296
322
  startIndex = Math.max(0, startIndex);
297
323
 
298
324
  // 溢出修正
299
- endIndex = Math.min(endIndex, dataSourceCopy.value.length);
325
+ endIndex = Math.min(endIndex, dataLength);
300
326
 
301
327
  if (startIndex >= endIndex) {
302
328
  // 兜底,不一定会执行到这里
@@ -308,7 +334,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
308
334
  }
309
335
 
310
336
  let offsetTop = 0;
311
- if (autoRowHeight) {
337
+ if (autoRowHeight || hasExpandCol.value) {
312
338
  offsetTop = autoRowHeightTop;
313
339
  } else {
314
340
  if (oldStartIndex === startIndex && oldEndIndex === endIndex) {
@@ -1,8 +1,8 @@
1
1
  import { Order, SortConfig, SortOption, SortState, StkTableColumn } from '../types';
2
2
 
3
3
  /** 是否空值 */
4
- function isEmptyValue(val: any, isNumber?: boolean) {
5
- let isEmpty = val === null || val === '' || val === void 0;
4
+ export function isEmptyValue(val: any, isNumber?: boolean) {
5
+ let isEmpty = val === null || val === void 0;
6
6
  if (isNumber) {
7
7
  isEmpty = isEmpty || typeof val === 'boolean' || Number.isNaN(+val);
8
8
  }
@@ -182,6 +182,7 @@ export function howDeepTheHeader(arr: StkTableColumn<any>[], level = 0) {
182
182
 
183
183
  /** number width +px */
184
184
  export function transformWidthToStr(width?: string | number) {
185
+ if (width === void 0) return;
185
186
  const numberWidth = Number(width);
186
187
  return width + (!Number.isNaN(numberWidth) ? 'px' : '');
187
188
  }