stk-table-vue 0.3.4 → 0.3.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.
package/README.md CHANGED
@@ -549,16 +549,19 @@ export type SortConfig<T extends Record<string, any>> = {
549
549
  ### 鼠标悬浮表头时,不展示title
550
550
  * 将 `StkTableColumn` 中的 `title` 字段置为 "" 空字符串。这样th中就没有title了。
551
551
  * 使用 `StkTableColumn` 中的 `customHeaderCell` 属性中,自定义表头渲染。
552
- ### 性能
553
- #### highlight
554
- * 在虚拟滚动下高亮强制使用 `css @keyframes` 实现动画。`setHighlightDimRow`/`setHighlightCellRow` 最后一个参数传入 `{method: 'css'}` 即可。(滚动后动画会中断)
555
- * 指定 `{method:'animation'}` 在虚拟滚动下使用animation api实现动画。好处是动画流畅,且滚动后动画不中断。坏处是不支持帧率配置。
552
+
553
+ ## Performance optimization
554
+ ### highlight
556
555
  * 配置 `props.highlightConfig.fps` 指定高亮帧率。降低帧率有利于性能。
557
- #### relative fixed
556
+ ### relative fixed
558
557
  * 配置 `props.cellFixedMode` 为 `relative` 时,将使用相对定位实现固定列与固定表头,相较于`sticky`的实现,渲染合成层更少。
559
558
  * 问题:若开启了纵向虚拟滚动,不开启横向虚拟滚动,且不设置某些列宽时。如果纵向滚动导致某些列宽变化,则会导致右侧固定列计算错误。
560
- #### tr 分层
561
- * 通过css选择器将 stk-table tbody tr 配置 `transform:translateZ(0)` 对每行 tr 进行分层。在 `customCell` 较多且复杂时,尝试开启此功能可能对性能有帮助。
559
+ ### tr 分层
560
+ * 通过css选择器将 stk-table tbody tr 配置 `transform:translateZ(0)` 对每行 tr 进行分层。对性能有帮助。
561
+ - 提升合成层可能导致黑底红字字体颜色发生变化。
562
+ - 以下情况尝试开启此功能。
563
+ - 在 `customCell` 较多且复杂时。
564
+ - 大量 highlight 动画时。
562
565
 
563
566
  ## Other
564
567
  * `$*$` 兼容注释
@@ -1,4 +1,4 @@
1
- import { HighlightConfig, Order, SeqConfig, SortConfig, SortOption, SortState, StkTableColumn, UniqKey, UniqKeyProp } from './types/index';
1
+ import { HighlightConfig, Order, SeqConfig, SortConfig, SortOption, SortState, StkTableColumn, UniqKeyProp } from './types/index';
2
2
  /** Generic stands for DataType */
3
3
  type DT = any;
4
4
  /**
@@ -191,7 +191,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
191
191
  duration?: number | undefined;
192
192
  }) => void;
193
193
  /** 设置高亮渐暗行 */
194
- setHighlightDimRow: (rowKeyValues: UniqKey[], option?: {
194
+ setHighlightDimRow: (rowKeyValues: import("./types/index").UniqKey[], option?: {
195
195
  method?: "animation" | "css" | "js" | undefined;
196
196
  useCss?: boolean | undefined;
197
197
  className?: string | undefined;
@@ -8,7 +8,10 @@ type Sorter<T> = boolean | ((data: T[], option: {
8
8
  export type CustomCellFunc<T extends Record<string, any>> = (props: {
9
9
  row: T;
10
10
  col: StkTableColumn<T>;
11
+ /** row[col.dataIndex] 的值 */
11
12
  cellValue: any;
13
+ rowIndex: number;
14
+ colIndex: number;
12
15
  }) => VNode;
13
16
  export type CustomHeaderCellFunc<T extends Record<string, any>> = (props: {
14
17
  col: StkTableColumn<T>;
@@ -12,7 +12,5 @@ type Params<DT extends Record<string, any>> = {
12
12
  export declare function useColResize<DT extends Record<string, any>>({ tableContainerRef, tableHeaderLast, colResizeIndicatorRef, props, emits, colKeyGen, }: Params<DT>): {
13
13
  isColResizing: Ref<boolean>;
14
14
  onThResizeMouseDown: (e: MouseEvent, col: StkTableColumn<DT>, isPrev?: boolean) => void;
15
- onThResizeMouseMove: (e: MouseEvent) => void;
16
- onThResizeMouseUp: (e: MouseEvent) => void;
17
15
  };
18
16
  export {};
@@ -1,4 +1,4 @@
1
- import { Order, SortConfig, SortOption, SortState, StkTableColumn } from './types';
1
+ import { Order, SortConfig, SortOption, SortState, StkTableColumn } from '../types';
2
2
  /**
3
3
  * 对有序数组插入新数据
4
4
  * @param sortState
@@ -0,0 +1,15 @@
1
+ import { Ref } from 'vue';
2
+ type UseTriggerRef<T> = {
3
+ getRef: () => Ref<T>;
4
+ getValue: () => T;
5
+ setValue: (v: T) => void;
6
+ triggerRef: () => void;
7
+ };
8
+ /**
9
+ * 创建一个可触发更新的引用对象。
10
+ * @template T 引用对象的类型。
11
+ * @param initialValue 初始值。
12
+ * @returns 包含获取引用、获取值、设置值和触发更新的函数的对象。
13
+ */
14
+ export declare function useTriggerRef<T>(initialValue: T): UseTriggerRef<T>;
15
+ export {};
@@ -260,10 +260,11 @@ function useColResize({
260
260
  const { clientX } = e;
261
261
  const { scrollLeft, scrollTop } = tableContainerRef.value;
262
262
  const { left } = tableContainerRef.value.getBoundingClientRect();
263
- let colIndex = tableHeaderLast.value.findIndex((it) => colKeyGen.value(it) === colKeyGen.value(col));
263
+ const tableHeaderLastValue = tableHeaderLast.value;
264
+ let colIndex = tableHeaderLastValue.findIndex((it) => colKeyGen.value(it) === colKeyGen.value(col));
264
265
  if (isPrev) {
265
266
  colIndex -= 1;
266
- col = tableHeaderLast.value[colIndex];
267
+ col = tableHeaderLastValue[colIndex];
267
268
  }
268
269
  const offsetTableX = clientX - left + scrollLeft;
269
270
  isColResizing.value = true;
@@ -337,9 +338,7 @@ function useColResize({
337
338
  }
338
339
  return {
339
340
  isColResizing,
340
- onThResizeMouseDown,
341
- onThResizeMouseMove,
342
- onThResizeMouseUp
341
+ onThResizeMouseDown
343
342
  };
344
343
  }
345
344
  function useFixedCol({ props, colKeyGen, tableHeaders, tableHeaderLast, tableContainerRef }) {
@@ -350,10 +349,11 @@ function useFixedCol({ props, colKeyGen, tableHeaders, tableHeaderLast, tableCon
350
349
  const fixedShadowCols = shallowRef([]);
351
350
  const fixedColClassMap = computed(() => {
352
351
  const colMap = /* @__PURE__ */ new Map();
352
+ const fixedShadowColsValue = fixedShadowCols.value;
353
353
  tableHeaders.value.forEach((cols) => {
354
354
  cols.forEach((col) => {
355
355
  const { showR, showL } = fixedShadow.value;
356
- const showShadow = props.fixedColShadow && col.fixed && (showL && col.fixed === "left" || showR && col.fixed === "right") && fixedShadowCols.value.includes(col);
356
+ const showShadow = props.fixedColShadow && col.fixed && (showL && col.fixed === "left" || showR && col.fixed === "right") && fixedShadowColsValue.includes(col);
357
357
  const classObj = {
358
358
  "fixed-cell": col.fixed,
359
359
  ["fixed-cell--" + col.fixed]: col.fixed,
@@ -367,10 +367,11 @@ function useFixedCol({ props, colKeyGen, tableHeaders, tableHeaderLast, tableCon
367
367
  function dealFixedColShadow() {
368
368
  if (!props.fixedColShadow)
369
369
  return;
370
- fixedShadowCols.value = [];
370
+ const fixedShadowColsTemp = [];
371
371
  let lastLeftCol = null;
372
- for (let i = tableHeaderLast.value.length - 1; i >= 0; i--) {
373
- const col = tableHeaderLast.value[i];
372
+ const tableHeaderLastValue = tableHeaderLast.value;
373
+ for (let i = tableHeaderLastValue.length - 1; i >= 0; i--) {
374
+ const col = tableHeaderLastValue[i];
374
375
  if (col.fixed === "left") {
375
376
  lastLeftCol = col;
376
377
  break;
@@ -379,16 +380,17 @@ function useFixedCol({ props, colKeyGen, tableHeaders, tableHeaderLast, tableCon
379
380
  let node = { __PARENT__: lastLeftCol };
380
381
  while (node = node.__PARENT__) {
381
382
  if (node.fixed) {
382
- fixedShadowCols.value.push(node);
383
+ fixedShadowColsTemp.push(node);
383
384
  }
384
385
  }
385
- const lastRightCol = tableHeaderLast.value.find((it) => it.fixed === "right");
386
+ const lastRightCol = tableHeaderLastValue.find((it) => it.fixed === "right");
386
387
  node = { __PARENT__: lastRightCol };
387
388
  while (node = node.__PARENT__) {
388
389
  if (node.fixed) {
389
- fixedShadowCols.value.push(node);
390
+ fixedShadowColsTemp.push(node);
390
391
  }
391
392
  }
393
+ fixedShadowCols.value = fixedShadowColsTemp;
392
394
  }
393
395
  function updateFixedShadow() {
394
396
  if (!props.fixedColShadow)
@@ -877,31 +879,33 @@ function useVirtualScroll({
877
879
  return props.virtualX && tableHeaderLast.value.reduce((sum, col) => sum += getCalculatedColWidth(col), 0) > virtualScrollX.value.containerWidth + 100;
878
880
  });
879
881
  const virtualX_columnPart = computed(() => {
882
+ const tableHeaderLastValue = tableHeaderLast.value;
880
883
  if (virtualX_on.value) {
881
884
  const leftCols = [];
882
885
  const rightCols = [];
883
886
  const { startIndex, endIndex } = virtualScrollX.value;
884
887
  for (let i = 0; i < startIndex; i++) {
885
- const col = tableHeaderLast.value[i];
886
- if (col.fixed === "left")
888
+ const col = tableHeaderLastValue[i];
889
+ if ((col == null ? void 0 : col.fixed) === "left")
887
890
  leftCols.push(col);
888
891
  }
889
- for (let i = endIndex; i < tableHeaderLast.value.length; i++) {
890
- const col = tableHeaderLast.value[i];
891
- if (col.fixed === "right")
892
+ for (let i = endIndex; i < tableHeaderLastValue.length; i++) {
893
+ const col = tableHeaderLastValue[i];
894
+ if ((col == null ? void 0 : col.fixed) === "right")
892
895
  rightCols.push(col);
893
896
  }
894
- const mainColumns = tableHeaderLast.value.slice(startIndex, endIndex);
897
+ const mainColumns = tableHeaderLastValue.slice(startIndex, endIndex);
895
898
  return leftCols.concat(mainColumns).concat(rightCols);
896
899
  }
897
- return tableHeaderLast.value;
900
+ return tableHeaderLastValue;
898
901
  });
899
902
  const virtualX_offsetRight = computed(() => {
900
903
  if (!virtualX_on.value)
901
904
  return 0;
902
905
  let width = 0;
903
- for (let i = virtualScrollX.value.endIndex; i < tableHeaderLast.value.length; i++) {
904
- const col = tableHeaderLast.value[i];
906
+ const tableHeaderLastValue = tableHeaderLast.value;
907
+ for (let i = virtualScrollX.value.endIndex; i < tableHeaderLastValue.length; i++) {
908
+ const col = tableHeaderLastValue[i];
905
909
  if (col.fixed !== "right") {
906
910
  width += getCalculatedColWidth(col);
907
911
  }
@@ -909,11 +913,15 @@ function useVirtualScroll({
909
913
  return width;
910
914
  });
911
915
  function initVirtualScrollY(height) {
916
+ if (height !== void 0 && typeof height !== "number") {
917
+ console.warn("initVirtualScrollY: height must be a number");
918
+ height = 0;
919
+ }
912
920
  if (!virtual_on.value)
913
921
  return;
914
922
  const { offsetHeight, scrollTop } = tableContainerRef.value || {};
915
923
  const { rowHeight } = virtualScroll.value;
916
- const containerHeight = height ?? (offsetHeight || DEFAULT_TABLE_HEIGHT);
924
+ const containerHeight = height || offsetHeight || DEFAULT_TABLE_HEIGHT;
917
925
  const { headless, headerRowHeight } = props;
918
926
  let pageSize = Math.ceil(containerHeight / rowHeight);
919
927
  if (!headless) {
@@ -973,10 +981,10 @@ function useVirtualScroll({
973
981
  }
974
982
  let vue2ScrollXTimeout = null;
975
983
  function updateVirtualScrollX(sLeft = 0) {
976
- var _a;
977
984
  if (!props.virtualX)
978
985
  return;
979
- const headerLength = (_a = tableHeaderLast.value) == null ? void 0 : _a.length;
986
+ const tableHeaderLastValue = tableHeaderLast.value;
987
+ const headerLength = tableHeaderLastValue == null ? void 0 : tableHeaderLastValue.length;
980
988
  if (!headerLength)
981
989
  return;
982
990
  const { scrollLeft } = virtualScrollX.value;
@@ -986,7 +994,7 @@ function useVirtualScroll({
986
994
  let leftColWidthSum = 0;
987
995
  let leftFirstColRestWidth = 0;
988
996
  for (let colIndex = 0; colIndex < headerLength; colIndex++) {
989
- const col = tableHeaderLast.value[colIndex];
997
+ const col = tableHeaderLastValue[colIndex];
990
998
  const colWidth = getCalculatedColWidth(col);
991
999
  startIndex++;
992
1000
  if (col.fixed === "left") {
@@ -1005,7 +1013,7 @@ function useVirtualScroll({
1005
1013
  const containerWidth = virtualScrollX.value.containerWidth - leftColWidthSum;
1006
1014
  let endIndex = headerLength;
1007
1015
  for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {
1008
- const col = tableHeaderLast.value[colIndex];
1016
+ const col = tableHeaderLastValue[colIndex];
1009
1017
  colWidthSum += getCalculatedColWidth(col);
1010
1018
  if (colWidthSum >= containerWidth) {
1011
1019
  endIndex = colIndex + 1;
@@ -1216,14 +1224,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1216
1224
  () => props.columns,
1217
1225
  () => {
1218
1226
  dealColumns();
1219
- nextTick(initVirtualScrollX);
1227
+ nextTick(() => {
1228
+ initVirtualScrollX();
1229
+ dealFixedColShadow();
1230
+ });
1220
1231
  }
1221
1232
  );
1222
1233
  watch(
1223
1234
  () => props.virtualX,
1224
1235
  () => {
1225
1236
  dealColumns();
1226
- nextTick(initVirtualScrollX);
1237
+ nextTick(() => {
1238
+ initVirtualScrollX();
1239
+ dealFixedColShadow();
1240
+ });
1227
1241
  }
1228
1242
  );
1229
1243
  watch(
@@ -1252,6 +1266,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1252
1266
  );
1253
1267
  watch(() => props.fixedColShadow, dealFixedColShadow);
1254
1268
  dealColumns();
1269
+ dealFixedColShadow();
1255
1270
  onMounted(() => {
1256
1271
  initVirtualScroll();
1257
1272
  updateFixedShadow();
@@ -1264,7 +1279,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1264
1279
  setSorter(dataIndex, order, { force: false, silent });
1265
1280
  }
1266
1281
  function dealColumns() {
1267
- tableHeaders.value = [];
1282
+ let tableHeadersTemp = [];
1268
1283
  const copyColumn = props.columns;
1269
1284
  const deep = howDeepTheHeader(copyColumn);
1270
1285
  const tempHeaderLast = [];
@@ -1272,8 +1287,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1272
1287
  console.error("多级表头不支持横向虚拟滚动");
1273
1288
  }
1274
1289
  function flat(arr, parent, depth = 0) {
1275
- if (!tableHeaders.value[depth]) {
1276
- tableHeaders.value[depth] = [];
1290
+ if (!tableHeadersTemp[depth]) {
1291
+ tableHeadersTemp[depth] = [];
1277
1292
  }
1278
1293
  let allChildrenLen = 0;
1279
1294
  let allChildrenWidthSum = 0;
@@ -1294,7 +1309,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1294
1309
  colWidth = getColWidth(col);
1295
1310
  tempHeaderLast.push(col);
1296
1311
  }
1297
- tableHeaders.value[depth].push(col);
1312
+ tableHeadersTemp[depth].push(col);
1298
1313
  const rowSpan = col.children ? 1 : deep - depth;
1299
1314
  const colSpan = colChildrenLen;
1300
1315
  if (rowSpan !== 1) {
@@ -1310,8 +1325,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1310
1325
  return [allChildrenLen, allChildrenWidthSum];
1311
1326
  }
1312
1327
  flat(copyColumn, null);
1328
+ tableHeaders.value = tableHeadersTemp;
1313
1329
  tableHeaderLast.value = tempHeaderLast;
1314
- dealFixedColShadow();
1315
1330
  }
1316
1331
  function rowKeyGen(row) {
1317
1332
  if (!row)
@@ -1706,10 +1721,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1706
1721
  key: 0,
1707
1722
  col,
1708
1723
  row,
1709
- "row-index": rowIndex,
1710
- "col-index": colIndex,
1711
- "cell-value": row[col.dataIndex]
1712
- }, null, 8, ["col", "row", "row-index", "col-index", "cell-value"])) : (openBlock(), createElementBlock("div", {
1724
+ rowIndex,
1725
+ colIndex,
1726
+ cellValue: row[col.dataIndex]
1727
+ }, null, 8, ["col", "row", "rowIndex", "colIndex", "cellValue"])) : (openBlock(), createElementBlock("div", {
1713
1728
  key: 1,
1714
1729
  class: "table-cell-wrapper",
1715
1730
  title: !col.type ? row[col.dataIndex] : ""
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stk-table-vue",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
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",
@@ -32,7 +32,7 @@
32
32
  "author": "japlus",
33
33
  "repository": {
34
34
  "type": "git",
35
- "url": "https://gitee.com/japlus/stk-table-vue"
35
+ "url": "https://github.com/ja-plus/stk-table-vue"
36
36
  },
37
37
  "license": "MIT",
38
38
  "devDependencies": {
@@ -176,9 +176,9 @@
176
176
  v-if="col.customCell"
177
177
  :col="col"
178
178
  :row="row"
179
- :row-index="rowIndex"
180
- :col-index="colIndex"
181
- :cell-value="row[col.dataIndex]"
179
+ :rowIndex="rowIndex"
180
+ :colIndex="colIndex"
181
+ :cellValue="row[col.dataIndex]"
182
182
  />
183
183
  <div v-else class="table-cell-wrapper" :title="!col.type ? row[col.dataIndex] : ''">
184
184
  <template v-if="col.type === 'seq'">
@@ -210,7 +210,7 @@
210
210
  */
211
211
  import { CSSProperties, computed, nextTick, onMounted, ref, shallowRef, toRaw, watch } from 'vue';
212
212
  import { DEFAULT_ROW_HEIGHT } from './const';
213
- import { HighlightConfig, Order, SeqConfig, SortConfig, SortOption, SortState, StkTableColumn, TagType, UniqKey, UniqKeyProp } from './types/index';
213
+ import { HighlightConfig, Order, SeqConfig, SortConfig, SortOption, SortState, StkTableColumn, TagType, UniqKeyProp } from './types/index';
214
214
  import { useAutoResize } from './useAutoResize';
215
215
  import { useColResize } from './useColResize';
216
216
  import { useFixedCol } from './useFixedCol';
@@ -219,7 +219,7 @@ import { useHighlight } from './useHighlight';
219
219
  import { useKeyboardArrowScroll } from './useKeyboardArrowScroll';
220
220
  import { useThDrag } from './useThDrag';
221
221
  import { useVirtualScroll } from './useVirtualScroll';
222
- import { createStkTableId, getCalculatedColWidth, getColWidth, howDeepTheHeader, tableSort, transformWidthToStr } from './utils';
222
+ import { createStkTableId, getCalculatedColWidth, getColWidth, howDeepTheHeader, tableSort, transformWidthToStr } from './utils/index';
223
223
 
224
224
  /** Generic stands for DataType */
225
225
  type DT = any;
@@ -596,14 +596,22 @@ watch(
596
596
  () => props.columns,
597
597
  () => {
598
598
  dealColumns();
599
- nextTick(initVirtualScrollX);
599
+ // initVirtualScrollX 需要获取容器滚动宽度等。必须等渲染完成后再调用。因此使用nextTick
600
+ nextTick(() => {
601
+ initVirtualScrollX();
602
+ dealFixedColShadow();
603
+ });
600
604
  },
601
605
  );
602
606
  watch(
603
607
  () => props.virtualX,
604
608
  () => {
605
609
  dealColumns();
606
- nextTick(initVirtualScrollX);
610
+ // initVirtualScrollX 需要获取容器滚动宽度等。必须等渲染完成后再调用。因此使用nextTick
611
+ nextTick(() => {
612
+ initVirtualScrollX();
613
+ dealFixedColShadow();
614
+ });
607
615
  },
608
616
  );
609
617
 
@@ -637,6 +645,7 @@ watch(
637
645
  watch(() => props.fixedColShadow, dealFixedColShadow);
638
646
 
639
647
  dealColumns();
648
+ dealFixedColShadow();
640
649
 
641
650
  onMounted(() => {
642
651
  initVirtualScroll();
@@ -656,7 +665,7 @@ function dealDefaultSorter() {
656
665
  */
657
666
  function dealColumns() {
658
667
  // reset
659
- tableHeaders.value = [];
668
+ let tableHeadersTemp: StkTableColumn<DT>[][] = [];
660
669
  const copyColumn = props.columns; // do not deep clone
661
670
  const deep = howDeepTheHeader(copyColumn);
662
671
  const tempHeaderLast: StkTableColumn<DT>[] = [];
@@ -673,8 +682,8 @@ function dealColumns() {
673
682
  * @param parentFixed 父节点固定列继承。
674
683
  */
675
684
  function flat(arr: StkTableColumn<DT>[], parent: StkTableColumn<DT> | null, depth = 0 /* , parentFixed: 'left' | 'right' | null = null */) {
676
- if (!tableHeaders.value[depth]) {
677
- tableHeaders.value[depth] = [];
685
+ if (!tableHeadersTemp[depth]) {
686
+ tableHeadersTemp[depth] = [];
678
687
  }
679
688
  /** 所有子节点数量 */
680
689
  let allChildrenLen = 0;
@@ -700,7 +709,7 @@ function dealColumns() {
700
709
  tempHeaderLast.push(col); // 没有children的列作为colgroup
701
710
  }
702
711
  // 回溯
703
- tableHeaders.value[depth].push(col);
712
+ tableHeadersTemp[depth].push(col);
704
713
  const rowSpan = col.children ? 1 : deep - depth;
705
714
  const colSpan = colChildrenLen;
706
715
  if (rowSpan !== 1) {
@@ -718,10 +727,8 @@ function dealColumns() {
718
727
 
719
728
  flat(copyColumn, null);
720
729
 
721
- // tableHeaders.value = [...tableHeaders.value];
722
-
730
+ tableHeaders.value = tableHeadersTemp;
723
731
  tableHeaderLast.value = tempHeaderLast;
724
- dealFixedColShadow();
725
732
  }
726
733
 
727
734
  /**
@@ -5,7 +5,15 @@ export type Order = null | 'asc' | 'desc';
5
5
 
6
6
  type Sorter<T> = boolean | ((data: T[], option: { order: Order; column: any }) => T[]);
7
7
 
8
- export type CustomCellFunc<T extends Record<string, any>> = (props: { row: T; col: StkTableColumn<T>; cellValue: any }) => VNode;
8
+ export type CustomCellFunc<T extends Record<string, any>> = (props: {
9
+ row: T;
10
+ col: StkTableColumn<T>;
11
+ /** row[col.dataIndex] 的值 */
12
+ cellValue: any;
13
+ rowIndex: number;
14
+ colIndex: number;
15
+ }) => VNode;
16
+
9
17
  export type CustomHeaderCellFunc<T extends Record<string, any>> = (props: { col: StkTableColumn<T> }) => VNode;
10
18
 
11
19
  /** 表格列配置 */
@@ -77,12 +77,13 @@ export function useColResize<DT extends Record<string, any>>({
77
77
  const { clientX } = e;
78
78
  const { scrollLeft, scrollTop } = tableContainerRef.value;
79
79
  const { left } = tableContainerRef.value.getBoundingClientRect();
80
+ const tableHeaderLastValue = tableHeaderLast.value;
80
81
  /** 列下标 */
81
- let colIndex = tableHeaderLast.value.findIndex(it => colKeyGen.value(it) === colKeyGen.value(col));
82
+ let colIndex = tableHeaderLastValue.findIndex(it => colKeyGen.value(it) === colKeyGen.value(col));
82
83
  if (isPrev) {
83
84
  // 上一列
84
85
  colIndex -= 1;
85
- col = tableHeaderLast.value[colIndex];
86
+ col = tableHeaderLastValue[colIndex];
86
87
  }
87
88
  const offsetTableX = clientX - left + scrollLeft;
88
89
 
@@ -175,7 +176,5 @@ export function useColResize<DT extends Record<string, any>>({
175
176
  return {
176
177
  isColResizing,
177
178
  onThResizeMouseDown,
178
- onThResizeMouseMove,
179
- onThResizeMouseUp,
180
179
  };
181
180
  }
@@ -29,6 +29,7 @@ export function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen,
29
29
 
30
30
  const fixedColClassMap = computed(() => {
31
31
  const colMap = new Map();
32
+ const fixedShadowColsValue = fixedShadowCols.value;
32
33
  tableHeaders.value.forEach(cols => {
33
34
  cols.forEach(col => {
34
35
  const { showR, showL } = fixedShadow.value;
@@ -36,7 +37,7 @@ export function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen,
36
37
  props.fixedColShadow &&
37
38
  col.fixed &&
38
39
  ((showL && col.fixed === 'left') || (showR && col.fixed === 'right')) &&
39
- fixedShadowCols.value.includes(col);
40
+ fixedShadowColsValue.includes(col);
40
41
  const classObj = {
41
42
  'fixed-cell': col.fixed,
42
43
  ['fixed-cell--' + col.fixed]: col.fixed,
@@ -51,11 +52,13 @@ export function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen,
51
52
  /** 处理固定列阴影 */
52
53
  function dealFixedColShadow() {
53
54
  if (!props.fixedColShadow) return;
54
- fixedShadowCols.value = [];
55
+ const fixedShadowColsTemp = [];
56
+
55
57
  // 找到最右边的固定列 findLast
56
58
  let lastLeftCol = null;
57
- for (let i = tableHeaderLast.value.length - 1; i >= 0; i--) {
58
- const col = tableHeaderLast.value[i];
59
+ const tableHeaderLastValue = tableHeaderLast.value;
60
+ for (let i = tableHeaderLastValue.length - 1; i >= 0; i--) {
61
+ const col = tableHeaderLastValue[i];
59
62
  if (col.fixed === 'left') {
60
63
  lastLeftCol = col;
61
64
  break;
@@ -65,18 +68,20 @@ export function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen,
65
68
  let node: any = { __PARENT__: lastLeftCol };
66
69
  while ((node = node.__PARENT__)) {
67
70
  if (node.fixed) {
68
- fixedShadowCols.value.push(node);
71
+ fixedShadowColsTemp.push(node);
69
72
  }
70
73
  }
71
74
 
72
75
  // 找到最左边的固定列
73
- const lastRightCol = tableHeaderLast.value.find(it => it.fixed === 'right');
76
+ const lastRightCol = tableHeaderLastValue.find(it => it.fixed === 'right');
74
77
  node = { __PARENT__: lastRightCol };
75
78
  while ((node = node.__PARENT__)) {
76
79
  if (node.fixed) {
77
- fixedShadowCols.value.push(node);
80
+ fixedShadowColsTemp.push(node);
78
81
  }
79
82
  }
83
+ // trigger
84
+ fixedShadowCols.value = fixedShadowColsTemp;
80
85
  }
81
86
 
82
87
  /** 滚动条变化时,更新需要展示阴影的列 */
@@ -103,34 +103,42 @@ export function useVirtualScroll<DT extends Record<string, any>>({
103
103
  });
104
104
 
105
105
  const virtualX_columnPart = computed(() => {
106
+ const tableHeaderLastValue = tableHeaderLast.value;
106
107
  if (virtualX_on.value) {
107
108
  // 虚拟横向滚动,固定列要一直保持存在
108
109
  const leftCols = [];
109
110
  const rightCols = [];
111
+ /**
112
+ * 存在问题:
113
+ * table columns 从多到少时。比方原来的start=5,end=10,现在start=4,end=8。这时候endIndex就超出数组范围了。
114
+ * FIXME: 如果新列数 < endIndex,此时需要重新计算列startIndex和endIndex。
115
+ */
110
116
  const { startIndex, endIndex } = virtualScrollX.value;
117
+
111
118
  // 左侧固定列,如果在左边不可见区。则需要拿出来放在前面
112
119
  for (let i = 0; i < startIndex; i++) {
113
- const col = tableHeaderLast.value[i];
114
- if (col.fixed === 'left') leftCols.push(col);
120
+ const col = tableHeaderLastValue[i];
121
+ if (col?.fixed === 'left') leftCols.push(col);
115
122
  }
116
123
  // 右侧固定列,如果在右边不可见区。则需要拿出来放在后面
117
- for (let i = endIndex; i < tableHeaderLast.value.length; i++) {
118
- const col = tableHeaderLast.value[i];
119
- if (col.fixed === 'right') rightCols.push(col);
124
+ for (let i = endIndex; i < tableHeaderLastValue.length; i++) {
125
+ const col = tableHeaderLastValue[i];
126
+ if (col?.fixed === 'right') rightCols.push(col);
120
127
  }
121
128
 
122
- const mainColumns = tableHeaderLast.value.slice(startIndex, endIndex);
129
+ const mainColumns = tableHeaderLastValue.slice(startIndex, endIndex);
123
130
 
124
131
  return leftCols.concat(mainColumns).concat(rightCols);
125
132
  }
126
- return tableHeaderLast.value;
133
+ return tableHeaderLastValue;
127
134
  });
128
135
 
129
136
  const virtualX_offsetRight = computed(() => {
130
137
  if (!virtualX_on.value) return 0;
131
138
  let width = 0;
132
- for (let i = virtualScrollX.value.endIndex; i < tableHeaderLast.value.length; i++) {
133
- const col = tableHeaderLast.value[i];
139
+ const tableHeaderLastValue = tableHeaderLast.value;
140
+ for (let i = virtualScrollX.value.endIndex; i < tableHeaderLastValue.length; i++) {
141
+ const col = tableHeaderLastValue[i];
134
142
  if (col.fixed !== 'right') {
135
143
  width += getCalculatedColWidth(col);
136
144
  }
@@ -143,10 +151,14 @@ export function useVirtualScroll<DT extends Record<string, any>>({
143
151
  * @param {number} [height] 虚拟滚动的高度
144
152
  */
145
153
  function initVirtualScrollY(height?: number) {
154
+ if (height !== void 0 && typeof height !== 'number') {
155
+ console.warn('initVirtualScrollY: height must be a number');
156
+ height = 0;
157
+ }
146
158
  if (!virtual_on.value) return;
147
159
  const { offsetHeight, scrollTop } = tableContainerRef.value || {};
148
160
  const { rowHeight } = virtualScroll.value;
149
- const containerHeight = height ?? (offsetHeight || DEFAULT_TABLE_HEIGHT);
161
+ const containerHeight = height || offsetHeight || DEFAULT_TABLE_HEIGHT;
150
162
  const { headless, headerRowHeight } = props;
151
163
  let pageSize = Math.ceil(containerHeight / rowHeight);
152
164
  if (!headless) {
@@ -228,7 +240,8 @@ export function useVirtualScroll<DT extends Record<string, any>>({
228
240
  /** 通过横向滚动条位置,计算横向虚拟滚动的参数 */
229
241
  function updateVirtualScrollX(sLeft = 0) {
230
242
  if (!props.virtualX) return;
231
- const headerLength = tableHeaderLast.value?.length;
243
+ const tableHeaderLastValue = tableHeaderLast.value;
244
+ const headerLength = tableHeaderLastValue?.length;
232
245
  if (!headerLength) return;
233
246
 
234
247
  const { scrollLeft } = virtualScrollX.value;
@@ -242,7 +255,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
242
255
  let leftFirstColRestWidth = 0;
243
256
 
244
257
  for (let colIndex = 0; colIndex < headerLength; colIndex++) {
245
- const col = tableHeaderLast.value[colIndex];
258
+ const col = tableHeaderLastValue[colIndex];
246
259
  const colWidth = getCalculatedColWidth(col);
247
260
  startIndex++;
248
261
  // fixed left 不进入计算列宽
@@ -264,7 +277,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
264
277
  const containerWidth = virtualScrollX.value.containerWidth - leftColWidthSum;
265
278
  let endIndex = headerLength;
266
279
  for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {
267
- const col = tableHeaderLast.value[colIndex];
280
+ const col = tableHeaderLastValue[colIndex];
268
281
  colWidthSum += getCalculatedColWidth(col);
269
282
  // 列宽大于容器宽度则停止
270
283
  if (colWidthSum >= containerWidth) {
@@ -1,5 +1,5 @@
1
- import { DEFAULT_COL_WIDTH, STK_ID_PREFIX } from './const';
2
- import { Order, SortConfig, SortOption, SortState, StkTableColumn } from './types';
1
+ import { DEFAULT_COL_WIDTH, STK_ID_PREFIX } from '../const';
2
+ import { Order, SortConfig, SortOption, SortState, StkTableColumn } from '../types';
3
3
 
4
4
  /** 是否空值 */
5
5
  function isEmptyValue(val: any, isNumber?: boolean) {
@@ -0,0 +1,33 @@
1
+ import { Ref, shallowRef } from 'vue';
2
+
3
+ type UseTriggerRef<T> = {
4
+ getRef: () => Ref<T>;
5
+ getValue: () => T;
6
+ setValue: (v: T) => void;
7
+ triggerRef: () => void;
8
+ };
9
+ /**
10
+ * 创建一个可触发更新的引用对象。
11
+ * @template T 引用对象的类型。
12
+ * @param initialValue 初始值。
13
+ * @returns 包含获取引用、获取值、设置值和触发更新的函数的对象。
14
+ */
15
+ export function useTriggerRef<T>(initialValue: T): UseTriggerRef<T> {
16
+ let value = initialValue;
17
+ const ref = shallowRef(value);
18
+
19
+ function getValue() {
20
+ return value;
21
+ }
22
+ function setValue(v: T) {
23
+ value = v;
24
+ }
25
+ function getRef() {
26
+ return ref;
27
+ }
28
+ function triggerRef() {
29
+ ref.value = value;
30
+ }
31
+
32
+ return { getRef, getValue, setValue, triggerRef };
33
+ }