stk-table-vue 0.0.1-beta.4 → 0.0.1-beta.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
@@ -1,7 +1,7 @@
1
- # StkTable
1
+ # StkTable (Sticky Table)
2
2
 
3
3
  Vue3 简易虚拟滚动表格。用于实时数据展示,新数据行高亮渐暗动效。
4
- js体积(38kb)
4
+ js体积(未压缩41kb)
5
5
 
6
6
  ## 功能
7
7
  * [x] 高亮行,单元格。
@@ -109,6 +109,18 @@ export type StkProps = Partial<{
109
109
 
110
110
  /** 可拖动至最小的列宽 */
111
111
  colMinWidth: number;
112
+
113
+ /**
114
+ * 单元格分割线。
115
+ * 默认横竖都有
116
+ * "h" - 仅展示横线
117
+ * "v" - 仅展示竖线
118
+ * "body-v" - 仅表体展示竖线
119
+ */
120
+ bordered: boolean | 'h' | 'v' | 'body-v';
121
+
122
+ /** 自动重新计算虚拟滚动高度宽度。默认true */
123
+ autoResize: boolean;
112
124
  }>;
113
125
  ```
114
126
 
@@ -151,12 +163,6 @@ export type StkTableColumn<T extends Record<string, any>> = {
151
163
  customHeaderCell?: Component | VNode | CustomHeaderCellFunc<T>;
152
164
  /** 二级表头 */
153
165
  children?: StkTableColumn<T>[];
154
- /**
155
- * 单元格分割线。
156
- * 默认横竖都有
157
- * horizontal - 仅展示横线
158
- */
159
- border: boolean | 'horizontal';
160
166
  };
161
167
  ```
162
168
 
@@ -1,12 +1,9 @@
1
+ import { SortOption, StkTableColumn } from './types/index';
1
2
  /**
2
- * @author JA+
3
- * 不支持低版本浏览器非虚拟滚动表格的表头固定,列固定,因为会卡。
4
- * TODO:存在的问题:
5
- * [] column.dataIndex 作为唯一键,不能重复
6
- * [] 计算的高亮颜色,挂在数据源上对象上,若多个表格使用同一个数据源对象会有问题。需要深拷贝。(解决方案:获取组件uid)
7
- * [] highlight-row 颜色不能恢复到active的颜色
3
+ * 初始化虚拟滚动参数
4
+ * @param {number} [height] 虚拟滚动的高度
8
5
  */
9
- import { SortOption, StkTableColumn } from '../StkTable/types/index';
6
+ declare function initVirtualScroll(height?: number): void;
10
7
  /**
11
8
  * 选中一行,
12
9
  * @param {string} rowKey
@@ -49,8 +46,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
49
46
  virtualX: boolean;
50
47
  columns: StkTableColumn<any>[];
51
48
  dataSource: any[];
52
- rowKey: import('../StkTable/types/index').UniqKey;
53
- colKey: import('../StkTable/types/index').UniqKey;
49
+ rowKey: import("./types/index").UniqKey;
50
+ colKey: import("./types/index").UniqKey;
54
51
  emptyCellText: string;
55
52
  noDataFull: boolean;
56
53
  showNoData: boolean;
@@ -63,6 +60,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
63
60
  colResizable: boolean;
64
61
  colMinWidth: number;
65
62
  bordered: boolean | "h" | "v" | "body-v";
63
+ autoResize: boolean;
66
64
  }>>, {
67
65
  width: string;
68
66
  fixedMode: boolean;
@@ -88,10 +86,15 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
88
86
  colResizable: boolean;
89
87
  colMinWidth: number;
90
88
  bordered: boolean;
89
+ autoResize: boolean;
91
90
  }>, {
91
+ initVirtualScroll: typeof initVirtualScroll;
92
+ initVirtualScrollX: () => void;
93
+ initVirtualScrollY: (height?: number | undefined) => void;
92
94
  setCurrentRow: typeof setCurrentRow;
93
95
  setHighlightDimCell: (rowKeyValue: string, dataIndex: string) => void;
94
96
  setHighlightDimRow: (rowKeyValues: (string | number)[]) => void;
97
+ sortCol: import("vue").Ref<string | null | undefined>;
95
98
  setSorter: typeof setSorter;
96
99
  resetSorter: typeof resetSorter;
97
100
  scrollTo: typeof scrollTo;
@@ -121,8 +124,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
121
124
  virtualX: boolean;
122
125
  columns: StkTableColumn<any>[];
123
126
  dataSource: any[];
124
- rowKey: import('../StkTable/types/index').UniqKey;
125
- colKey: import('../StkTable/types/index').UniqKey;
127
+ rowKey: import("./types/index").UniqKey;
128
+ colKey: import("./types/index").UniqKey;
126
129
  emptyCellText: string;
127
130
  noDataFull: boolean;
128
131
  showNoData: boolean;
@@ -135,6 +138,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
135
138
  colResizable: boolean;
136
139
  colMinWidth: number;
137
140
  bordered: boolean | "h" | "v" | "body-v";
141
+ autoResize: boolean;
138
142
  }>>, {
139
143
  width: string;
140
144
  fixedMode: boolean;
@@ -160,6 +164,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
160
164
  colResizable: boolean;
161
165
  colMinWidth: number;
162
166
  bordered: boolean;
167
+ autoResize: boolean;
163
168
  }>>> & {
164
169
  onScroll?: ((...args: any[]) => any) | undefined;
165
170
  "onTh-drag-start"?: ((...args: any[]) => any) | undefined;
@@ -178,7 +183,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
178
183
  width: string;
179
184
  minWidth: string;
180
185
  maxWidth: string;
181
- colKey: import('../StkTable/types/index').UniqKey;
186
+ colKey: import("./types/index").UniqKey;
182
187
  fixedMode: boolean;
183
188
  headless: boolean;
184
189
  theme: "light" | "dark";
@@ -186,7 +191,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
186
191
  virtualX: boolean;
187
192
  columns: StkTableColumn<any>[];
188
193
  dataSource: any[];
189
- rowKey: import('../StkTable/types/index').UniqKey;
194
+ rowKey: import("./types/index").UniqKey;
190
195
  emptyCellText: string;
191
196
  noDataFull: boolean;
192
197
  showNoData: boolean;
@@ -199,6 +204,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
199
204
  colResizable: boolean;
200
205
  colMinWidth: number;
201
206
  bordered: boolean | "h" | "v" | "body-v";
207
+ autoResize: boolean;
202
208
  }, {}>, {
203
209
  tableHeader?(_: {
204
210
  column: StkTableColumn<any>;
@@ -1,2 +1,3 @@
1
1
  export { default as StkTable } from './StkTable.vue';
2
2
  export { tableSort, insertToOrderedArray } from './utils';
3
+ export type { StkTableColumn } from './types/index';
@@ -118,5 +118,10 @@ export type StkProps = Partial<{
118
118
  * "body-v" - 仅表体展示竖线
119
119
  */
120
120
  bordered: boolean | 'h' | 'v' | 'body-v';
121
+ /**
122
+ * 自动重新计算虚拟滚动高度宽度。默认true
123
+ * [非响应式]
124
+ */
125
+ autoResize: boolean;
121
126
  }>;
122
127
  export {};
@@ -0,0 +1,15 @@
1
+ import { Ref } from 'vue';
2
+ type Options = {
3
+ tableContainer: Ref<HTMLElement | undefined>;
4
+ initVirtualScroll: () => void;
5
+ scrollTo: () => void;
6
+ props: any;
7
+ /** 防抖延时 */
8
+ debounceMs: number;
9
+ };
10
+ /**
11
+ * 窗口变化自动重置虚拟滚动
12
+ * @param param0
13
+ */
14
+ export declare function useAutoResize({ tableContainer, initVirtualScroll, scrollTo, props, debounceMs }: Options): void;
15
+ export {};
@@ -1,4 +1,4 @@
1
- import { ref, onMounted, onBeforeUnmount, computed, defineComponent, shallowRef, watch, toRaw, openBlock, createElementBlock, normalizeClass, unref, normalizeStyle, withDirectives, createElementVNode, vShow, Fragment, renderList, createCommentVNode, createBlock, resolveDynamicComponent, renderSlot, toDisplayString, createTextVNode, pushScopeId, popScopeId } from "vue";
1
+ import { onMounted, onBeforeUnmount, watch, ref, computed, defineComponent, shallowRef, toRaw, openBlock, createElementBlock, normalizeClass, unref, normalizeStyle, withDirectives, createElementVNode, vShow, Fragment, renderList, createCommentVNode, createBlock, resolveDynamicComponent, renderSlot, toDisplayString, createTextVNode } from "vue";
2
2
  import { interpolateRgb } from "d3-interpolate";
3
3
  const Default_Col_Width = "100";
4
4
  const Default_Table_Height = 100;
@@ -19,6 +19,54 @@ try {
19
19
  console.error("Cannot get Chrome version", e);
20
20
  }
21
21
  const Is_Legacy_Mode = _chromeVersion < 56;
22
+ function useAutoResize({ tableContainer, initVirtualScroll, scrollTo, props, debounceMs }) {
23
+ let resizeObserver = null;
24
+ onMounted(() => {
25
+ initResizeObserver();
26
+ });
27
+ onBeforeUnmount(() => {
28
+ removeResizeObserver();
29
+ });
30
+ function initResizeObserver() {
31
+ if (window.ResizeObserver) {
32
+ if (!tableContainer.value) {
33
+ const watchDom = watch(
34
+ () => tableContainer,
35
+ () => {
36
+ initResizeObserver();
37
+ watchDom();
38
+ }
39
+ );
40
+ return;
41
+ }
42
+ resizeObserver = new ResizeObserver(resizeCallback);
43
+ resizeObserver.observe(tableContainer.value);
44
+ } else {
45
+ window.addEventListener("resize", resizeCallback);
46
+ }
47
+ }
48
+ function removeResizeObserver() {
49
+ if (resizeObserver) {
50
+ resizeObserver.disconnect();
51
+ resizeObserver = null;
52
+ } else {
53
+ window.removeEventListener("resize", resizeCallback);
54
+ }
55
+ }
56
+ let debounceTime = 0;
57
+ function resizeCallback() {
58
+ if (debounceTime) {
59
+ window.clearTimeout(debounceTime);
60
+ }
61
+ debounceTime = window.setTimeout(() => {
62
+ if (props.autoResize) {
63
+ scrollTo();
64
+ initVirtualScroll();
65
+ }
66
+ debounceTime = 0;
67
+ }, debounceMs);
68
+ }
69
+ }
22
70
  function useColResize({ tableContainer, tableHeaderLast, colResizeIndicator, props, emit, colKeyGen }) {
23
71
  const isColResizing = ref(false);
24
72
  let colResizeState = {
@@ -328,17 +376,17 @@ function useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLa
328
376
  });
329
377
  function initVirtualScrollY(height) {
330
378
  var _a, _b;
331
- if (virtual_on.value) {
332
- virtualScroll.value.containerHeight = typeof height === "number" ? height : ((_a = tableContainer.value) == null ? void 0 : _a.offsetHeight) || Default_Table_Height;
333
- updateVirtualScrollY((_b = tableContainer.value) == null ? void 0 : _b.scrollTop);
334
- }
379
+ if (!virtual_on.value)
380
+ return;
381
+ virtualScroll.value.containerHeight = typeof height === "number" ? height : ((_a = tableContainer.value) == null ? void 0 : _a.offsetHeight) || Default_Table_Height;
382
+ updateVirtualScrollY((_b = tableContainer.value) == null ? void 0 : _b.scrollTop);
335
383
  }
336
384
  function initVirtualScrollX() {
337
- if (props.virtualX) {
338
- const { offsetWidth, scrollLeft } = tableContainer.value || {};
339
- virtualScrollX.value.containerWidth = offsetWidth || Default_Table_Width;
340
- updateVirtualScrollX(scrollLeft);
341
- }
385
+ if (!props.virtualX)
386
+ return;
387
+ const { offsetWidth, scrollLeft } = tableContainer.value || {};
388
+ virtualScrollX.value.containerWidth = offsetWidth || Default_Table_Width;
389
+ updateVirtualScrollX(scrollLeft);
342
390
  }
343
391
  function updateVirtualScrollY(sTop = 0) {
344
392
  const { rowHeight } = virtualScroll.value;
@@ -444,6 +492,8 @@ function strCompare(a, b, type) {
444
492
  }
445
493
  }
446
494
  function tableSort(sortOption, order, dataSource) {
495
+ if (!(dataSource == null ? void 0 : dataSource.length))
496
+ return dataSource || [];
447
497
  let targetDataSource = [...dataSource];
448
498
  if (typeof sortOption.sorter === "function") {
449
499
  const customSorterData = sortOption.sorter(targetDataSource, { order, column: sortOption });
@@ -492,7 +542,6 @@ function howDeepTheColumn(arr, level = 1) {
492
542
  });
493
543
  return Math.max(...levels);
494
544
  }
495
- const _withScopeId = (n) => (pushScopeId("data-v-0aa41491"), n = n(), popScopeId(), n);
496
545
  const _hoisted_1 = { key: 0 };
497
546
  const _hoisted_2 = ["data-col-key", "draggable", "rowspan", "colspan", "title", "onClick"];
498
547
  const _hoisted_3 = { class: "table-header-cell-wrapper" };
@@ -501,7 +550,7 @@ const _hoisted_5 = {
501
550
  key: 2,
502
551
  class: "table-header-sorter"
503
552
  };
504
- const _hoisted_6 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ createElementVNode("svg", {
553
+ const _hoisted_6 = /* @__PURE__ */ createElementVNode("svg", {
505
554
  xmlns: "http://www.w3.org/2000/svg",
506
555
  width: "16px",
507
556
  height: "16px",
@@ -519,7 +568,7 @@ const _hoisted_6 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ createElem
519
568
  points: "8 10 4.8 14 11.2 14"
520
569
  })
521
570
  ])
522
- ], -1));
571
+ ], -1);
523
572
  const _hoisted_7 = [
524
573
  _hoisted_6
525
574
  ];
@@ -564,7 +613,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
564
613
  rowClassName: { type: Function, default: () => "" },
565
614
  colResizable: { type: Boolean, default: false },
566
615
  colMinWidth: { default: 10 },
567
- bordered: { type: [Boolean, String], default: true }
616
+ bordered: { type: [Boolean, String], default: true },
617
+ autoResize: { type: Boolean, default: true }
568
618
  },
569
619
  emits: [
570
620
  "sort-change",
@@ -608,15 +658,19 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
608
658
  const store = {};
609
659
  const cols = [...tableHeaderLast.value];
610
660
  let left = 0;
661
+ let rightStartIndex = 0;
611
662
  for (let i = 0; i < cols.length; i++) {
612
663
  const item = cols[i];
613
664
  if (item.fixed === "left") {
614
665
  store[item.dataIndex] = left;
615
666
  left += parseInt(item.width || Default_Col_Width);
616
667
  }
668
+ if (!rightStartIndex && item.fixed === "right") {
669
+ rightStartIndex = i;
670
+ }
617
671
  }
618
672
  let right = 0;
619
- for (let i = cols.length - 1; i >= 0; i--) {
673
+ for (let i = cols.length - 1; i >= rightStartIndex; i--) {
620
674
  const item = cols[i];
621
675
  if (item.fixed === "right") {
622
676
  store[item.dataIndex] = right;
@@ -649,6 +703,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
649
703
  updateVirtualScrollX
650
704
  } = useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLast });
651
705
  const { setHighlightDimCell, setHighlightDimRow } = useHighlight({ props, tableContainer, rowKeyGen });
706
+ if (props.autoResize) {
707
+ useAutoResize({ tableContainer, initVirtualScroll, scrollTo, props, debounceMs: 500 });
708
+ }
652
709
  watch(
653
710
  () => props.columns,
654
711
  () => {
@@ -660,6 +717,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
660
717
  watch(
661
718
  () => props.dataSource,
662
719
  (val) => {
720
+ if (!val) {
721
+ console.warn("invalid dataSource");
722
+ return;
723
+ }
663
724
  let needInitVirtualScrollY = false;
664
725
  if (dataSourceCopy.value.length !== val.length) {
665
726
  needInitVirtualScrollY = true;
@@ -904,9 +965,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
904
965
  return toRaw(dataSourceCopy.value);
905
966
  }
906
967
  __expose({
968
+ initVirtualScroll,
969
+ initVirtualScrollX,
970
+ initVirtualScrollY,
907
971
  setCurrentRow,
908
972
  setHighlightDimCell,
909
973
  setHighlightDimRow,
974
+ sortCol,
910
975
  setSorter,
911
976
  resetSorter,
912
977
  scrollTo,
@@ -972,7 +1037,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
972
1037
  col.dataIndex === unref(sortCol) && unref(sortOrderIndex) !== 0 && "sorter-" + sortSwitchOrder[unref(sortOrderIndex)],
973
1038
  _ctx.showHeaderOverflow ? "text-overflow" : "",
974
1039
  col.headerClassName,
975
- col.fixed ? "fixed-cell" : ""
1040
+ col.fixed ? "fixed-cell" : "",
1041
+ col.fixed ? "fixed-cell--" + col.fixed : ""
976
1042
  ]),
977
1043
  onClick: (e) => {
978
1044
  onColumnSort(col);
@@ -994,7 +1060,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
994
1060
  column: col
995
1061
  }, () => [
996
1062
  createElementVNode("span", _hoisted_4, toDisplayString(col.title), 1)
997
- ], true),
1063
+ ]),
998
1064
  col.sorter ? (openBlock(), createElementBlock("span", _hoisted_5, _hoisted_7)) : createCommentVNode("", true),
999
1065
  _ctx.colResizable && colIndex > 0 ? (openBlock(), createElementBlock("div", {
1000
1066
  key: 3,
@@ -1055,7 +1121,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1055
1121
  return openBlock(), createElementBlock("td", {
1056
1122
  key: col.dataIndex,
1057
1123
  "data-index": col.dataIndex,
1058
- class: normalizeClass([col.className, _ctx.showOverflow ? "text-overflow" : "", col.fixed ? "fixed-cell" : ""]),
1124
+ class: normalizeClass([
1125
+ col.className,
1126
+ _ctx.showOverflow ? "text-overflow" : "",
1127
+ col.fixed ? "fixed-cell" : "",
1128
+ col.fixed ? "fixed-cell--" + col.fixed : ""
1129
+ ]),
1059
1130
  style: normalizeStyle(getCellStyle(2, col)),
1060
1131
  onClick: (e) => onCellClick(e, row, col)
1061
1132
  }, [
@@ -1085,22 +1156,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1085
1156
  }, [
1086
1157
  renderSlot(_ctx.$slots, "empty", {}, () => [
1087
1158
  createTextVNode("暂无数据")
1088
- ], true)
1159
+ ])
1089
1160
  ], 2)) : createCommentVNode("", true)
1090
1161
  ], 38);
1091
1162
  };
1092
1163
  }
1093
1164
  });
1094
- const _export_sfc = (sfc, props) => {
1095
- const target = sfc.__vccOpts || sfc;
1096
- for (const [key, val] of props) {
1097
- target[key] = val;
1098
- }
1099
- return target;
1100
- };
1101
- const StkTable = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-0aa41491"]]);
1102
1165
  export {
1103
- StkTable,
1166
+ _sfc_main as StkTable,
1104
1167
  insertToOrderedArray,
1105
1168
  tableSort
1106
1169
  };
package/lib/style.css CHANGED
@@ -1,4 +1,4 @@
1
- .stk-table[data-v-0aa41491] {
1
+ .stk-table {
2
2
  --row-height: 28px;
3
3
  --cell-padding-x: 8px;
4
4
  --resize-handle-width: 4px;
@@ -28,7 +28,7 @@
28
28
  /** 列宽调整指示器 */
29
29
  /**虚拟滚动模式 */
30
30
  }
31
- .stk-table.dark[data-v-0aa41491] {
31
+ .stk-table.dark {
32
32
  --th-bgc: #181c21;
33
33
  --td-bgc: #181c21;
34
34
  --border-color: #26292e;
@@ -43,45 +43,45 @@
43
43
  --col-resize-indicator-color: #5d6064;
44
44
  color: #d0d1d2;
45
45
  }
46
- .stk-table.headless[data-v-0aa41491] {
46
+ .stk-table.headless {
47
47
  border-top: 1px solid var(--border-color);
48
48
  }
49
- .stk-table.is-col-resizing th[data-v-0aa41491] {
49
+ .stk-table.is-col-resizing th {
50
50
  pointer-events: none;
51
51
  }
52
- .stk-table.border-h[data-v-0aa41491] {
52
+ .stk-table.border-h {
53
53
  --bg-border-right: linear-gradient(transparent, transparent);
54
54
  --bg-border-left: linear-gradient(transparent, transparent);
55
55
  }
56
- .stk-table.border-v[data-v-0aa41491] {
56
+ .stk-table.border-v {
57
57
  --bg-border-bottom: linear-gradient(transparent, transparent);
58
58
  }
59
- .stk-table.border .stk-table-main th[data-v-0aa41491],
60
- .stk-table.border .stk-table-main td[data-v-0aa41491] {
59
+ .stk-table.border .stk-table-main th,
60
+ .stk-table.border .stk-table-main td {
61
61
  background-image: var(--bg-border-right), var(--bg-border-bottom);
62
62
  }
63
- .stk-table.border .stk-table-main thead tr:first-child th[data-v-0aa41491] {
63
+ .stk-table.border .stk-table-main thead tr:first-child th {
64
64
  background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
65
65
  }
66
- .stk-table.border .stk-table-main thead tr:first-child th[data-v-0aa41491]:first-child {
66
+ .stk-table.border .stk-table-main thead tr:first-child th:first-child {
67
67
  background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
68
68
  }
69
- .stk-table.border .stk-table-main thead tr th[data-v-0aa41491]:first-child {
69
+ .stk-table.border .stk-table-main thead tr th:first-child {
70
70
  background-image: var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
71
71
  }
72
- .stk-table.border .stk-table-main tbody td[data-v-0aa41491]:first-child {
72
+ .stk-table.border .stk-table-main tbody td:first-child {
73
73
  background-image: var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
74
74
  }
75
- .stk-table.border.virtual-x .stk-table-main thead tr:first-child .virtual-x-left + th[data-v-0aa41491] {
75
+ .stk-table.border.virtual-x .stk-table-main thead tr:first-child .virtual-x-left + th {
76
76
  background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
77
77
  }
78
- .stk-table.border.virtual-x .stk-table-main tr .virtual-x-left + th[data-v-0aa41491] {
78
+ .stk-table.border.virtual-x .stk-table-main tr .virtual-x-left + th {
79
79
  background-image: var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
80
80
  }
81
- .stk-table.border-body-v .stk-table-main tbody[data-v-0aa41491] {
81
+ .stk-table.border-body-v .stk-table-main tbody {
82
82
  --bg-border-bottom: linear-gradient(transparent, transparent);
83
83
  }
84
- .stk-table .column-resize-indicator[data-v-0aa41491] {
84
+ .stk-table .column-resize-indicator {
85
85
  width: 0;
86
86
  height: 100%;
87
87
  border-left: 1px dashed var(--col-resize-indicator-color);
@@ -90,122 +90,131 @@
90
90
  display: none;
91
91
  pointer-events: none;
92
92
  }
93
- .stk-table .stk-table-main[data-v-0aa41491] {
93
+ .stk-table .stk-table-main {
94
94
  border-spacing: 0;
95
95
  border-collapse: separate;
96
+ width: fit-content;
97
+ min-width: 100%;
96
98
  }
97
- .stk-table .stk-table-main.fixed-mode[data-v-0aa41491] {
99
+ .stk-table .stk-table-main.fixed-mode {
98
100
  table-layout: fixed;
99
101
  }
100
- .stk-table .stk-table-main th[data-v-0aa41491],
101
- .stk-table .stk-table-main td[data-v-0aa41491] {
102
+ .stk-table .stk-table-main th,
103
+ .stk-table .stk-table-main td {
102
104
  z-index: 1;
103
105
  height: var(--row-height);
104
106
  font-size: 14px;
105
107
  box-sizing: border-box;
106
108
  padding: 0 var(--cell-padding-x);
107
109
  }
108
- .stk-table .stk-table-main thead tr:first-child th[data-v-0aa41491] {
110
+ .stk-table .stk-table-main thead tr:first-child th {
109
111
  position: sticky;
110
112
  top: 0;
111
113
  }
112
- .stk-table .stk-table-main thead tr th[data-v-0aa41491] {
114
+ .stk-table .stk-table-main thead tr th {
113
115
  background-color: var(--th-bgc);
114
116
  }
115
- .stk-table .stk-table-main thead tr th.sortable[data-v-0aa41491] {
117
+ .stk-table .stk-table-main thead tr th.sortable {
116
118
  cursor: pointer;
117
119
  }
118
- .stk-table .stk-table-main thead tr th.text-overflow .table-header-cell-wrapper[data-v-0aa41491] {
120
+ .stk-table .stk-table-main thead tr th.text-overflow .table-header-cell-wrapper {
119
121
  white-space: nowrap;
120
122
  overflow: hidden;
121
123
  }
122
- .stk-table .stk-table-main thead tr th.text-overflow .table-header-cell-wrapper .table-header-title[data-v-0aa41491] {
124
+ .stk-table .stk-table-main thead tr th.text-overflow .table-header-cell-wrapper .table-header-title {
123
125
  text-overflow: ellipsis;
124
126
  overflow: hidden;
125
127
  }
126
- .stk-table .stk-table-main thead tr th:not(.sorter-desc):not(.sorter-asc):hover .table-header-cell-wrapper .table-header-sorter #arrow-up[data-v-0aa41491] {
128
+ .stk-table .stk-table-main thead tr th:not(.sorter-desc):not(.sorter-asc):hover .table-header-cell-wrapper .table-header-sorter #arrow-up {
127
129
  fill: var(--sort-arrow-hover-color);
128
130
  }
129
- .stk-table .stk-table-main thead tr th:not(.sorter-desc):not(.sorter-asc):hover .table-header-cell-wrapper .table-header-sorter #arrow-down[data-v-0aa41491] {
131
+ .stk-table .stk-table-main thead tr th:not(.sorter-desc):not(.sorter-asc):hover .table-header-cell-wrapper .table-header-sorter #arrow-down {
130
132
  fill: var(--sort-arrow-hover-color);
131
133
  }
132
- .stk-table .stk-table-main thead tr th.sorter-desc .table-header-cell-wrapper .table-header-sorter #arrow-up[data-v-0aa41491] {
134
+ .stk-table .stk-table-main thead tr th.sorter-desc .table-header-cell-wrapper .table-header-sorter {
135
+ display: initial;
136
+ }
137
+ .stk-table .stk-table-main thead tr th.sorter-desc .table-header-cell-wrapper .table-header-sorter #arrow-up {
133
138
  fill: var(--sort-arrow-active-sub-color);
134
139
  }
135
- .stk-table .stk-table-main thead tr th.sorter-desc .table-header-cell-wrapper .table-header-sorter #arrow-down[data-v-0aa41491] {
140
+ .stk-table .stk-table-main thead tr th.sorter-desc .table-header-cell-wrapper .table-header-sorter #arrow-down {
136
141
  fill: var(--sort-arrow-active-color);
137
142
  }
138
- .stk-table .stk-table-main thead tr th.sorter-asc .table-header-cell-wrapper .table-header-sorter #arrow-up[data-v-0aa41491] {
143
+ .stk-table .stk-table-main thead tr th.sorter-asc .table-header-cell-wrapper .table-header-sorter {
144
+ display: initial;
145
+ }
146
+ .stk-table .stk-table-main thead tr th.sorter-asc .table-header-cell-wrapper .table-header-sorter #arrow-up {
139
147
  fill: var(--sort-arrow-active-color);
140
148
  }
141
- .stk-table .stk-table-main thead tr th.sorter-asc .table-header-cell-wrapper .table-header-sorter #arrow-down[data-v-0aa41491] {
149
+ .stk-table .stk-table-main thead tr th.sorter-asc .table-header-cell-wrapper .table-header-sorter #arrow-down {
142
150
  fill: var(--sort-arrow-active-sub-color);
143
151
  }
144
- .stk-table .stk-table-main thead tr th .table-header-cell-wrapper[data-v-0aa41491] {
152
+ .stk-table .stk-table-main thead tr th .table-header-cell-wrapper {
145
153
  max-width: 100%;
146
154
  display: inline-flex;
147
155
  align-items: center;
148
156
  }
149
- .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-title[data-v-0aa41491] {
157
+ .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-title {
150
158
  overflow: hidden;
151
159
  align-self: flex-start;
152
160
  }
153
- .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-sorter[data-v-0aa41491] {
161
+ .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-sorter {
154
162
  flex-shrink: 0;
155
163
  margin-left: 4px;
156
164
  width: 16px;
157
165
  height: 16px;
166
+ display: none;
158
167
  }
159
- .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-sorter #arrow-up[data-v-0aa41491],
160
- .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-sorter #arrow-down[data-v-0aa41491] {
168
+ .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-sorter #arrow-up,
169
+ .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-sorter #arrow-down {
161
170
  fill: var(--sort-arrow-color);
162
171
  }
163
- .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-resizer[data-v-0aa41491] {
172
+ .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-resizer {
164
173
  position: absolute;
165
174
  top: 0;
166
175
  bottom: 0;
167
176
  cursor: col-resize;
168
177
  width: var(--resize-handle-width);
169
178
  }
170
- .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-resizer.left[data-v-0aa41491] {
179
+ .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-resizer.left {
171
180
  left: 0;
172
181
  }
173
- .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-resizer.right[data-v-0aa41491] {
182
+ .stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-resizer.right {
174
183
  right: 0;
175
184
  }
176
- .stk-table .stk-table-main tbody[data-v-0aa41491] {
185
+ .stk-table .stk-table-main tbody {
177
186
  /**高亮渐暗 */
178
187
  }
179
- @keyframes dim-0aa41491 {
188
+ @keyframes dim {
180
189
  from {
181
190
  background-color: var(--highlight-color);
182
191
  }
183
192
  }
184
- .stk-table .stk-table-main tbody tr[data-v-0aa41491] {
193
+ .stk-table .stk-table-main tbody tr {
185
194
  background-color: var(--td-bgc);
186
195
  }
187
- .stk-table .stk-table-main tbody tr.highlight-row[data-v-0aa41491] {
188
- animation: dim-0aa41491 2s linear;
196
+ .stk-table .stk-table-main tbody tr.highlight-row {
197
+ animation: dim 2s linear;
189
198
  }
190
- .stk-table .stk-table-main tbody tr.hover[data-v-0aa41491],
191
- .stk-table .stk-table-main tbody tr[data-v-0aa41491]:hover {
199
+ .stk-table .stk-table-main tbody tr.hover,
200
+ .stk-table .stk-table-main tbody tr:hover {
192
201
  background-color: var(--tr-hover-bgc);
193
202
  }
194
- .stk-table .stk-table-main tbody tr.active[data-v-0aa41491] {
203
+ .stk-table .stk-table-main tbody tr.active {
195
204
  background-color: var(--tr-active-bgc);
196
205
  }
197
- .stk-table .stk-table-main tbody tr td.fixed-cell[data-v-0aa41491] {
206
+ .stk-table .stk-table-main tbody tr td.fixed-cell {
198
207
  background-color: inherit;
199
208
  }
200
- .stk-table .stk-table-main tbody tr td.highlight-cell[data-v-0aa41491] {
201
- animation: dim-0aa41491 2s linear;
209
+ .stk-table .stk-table-main tbody tr td.highlight-cell {
210
+ animation: dim 2s linear;
202
211
  }
203
- .stk-table .stk-table-main tbody tr td.text-overflow .table-cell-wrapper[data-v-0aa41491] {
212
+ .stk-table .stk-table-main tbody tr td.text-overflow .table-cell-wrapper {
204
213
  white-space: nowrap;
205
214
  overflow: hidden;
206
215
  text-overflow: ellipsis;
207
216
  }
208
- .stk-table .stk-table-no-data[data-v-0aa41491] {
217
+ .stk-table .stk-table-no-data {
209
218
  background-color: var(--table-bgc);
210
219
  line-height: var(--row-height);
211
220
  text-align: center;
@@ -220,27 +229,27 @@ from {
220
229
  align-items: center;
221
230
  justify-content: center;
222
231
  }
223
- .stk-table .stk-table-no-data.no-data-full[data-v-0aa41491] {
232
+ .stk-table .stk-table-no-data.no-data-full {
224
233
  flex: 1;
225
234
  }
226
- .stk-table.virtual .stk-table-main thead tr th .table-header-cell-wrapper[data-v-0aa41491] {
235
+ .stk-table.virtual .stk-table-main thead tr th .table-header-cell-wrapper {
227
236
  overflow: hidden;
228
237
  max-height: var(--row-height);
229
238
  }
230
- .stk-table.virtual .stk-table-main tbody[data-v-0aa41491] {
239
+ .stk-table.virtual .stk-table-main tbody {
231
240
  position: relative;
232
241
  }
233
- .stk-table.virtual .stk-table-main tbody tr.padding-top-tr td[data-v-0aa41491] {
242
+ .stk-table.virtual .stk-table-main tbody tr.padding-top-tr td {
234
243
  height: 0;
235
244
  }
236
- .stk-table.virtual .stk-table-main tbody tr td[data-v-0aa41491] {
245
+ .stk-table.virtual .stk-table-main tbody tr td {
237
246
  height: var(--row-height);
238
247
  line-height: 1;
239
248
  }
240
- .stk-table.virtual .stk-table-main tbody tr td .table-cell-wrapper[data-v-0aa41491] {
249
+ .stk-table.virtual .stk-table-main tbody tr td .table-cell-wrapper {
241
250
  max-height: var(--row-height);
242
251
  overflow: hidden;
243
252
  }
244
- .stk-table.virtual-x .stk-table-main .virtual-x-left[data-v-0aa41491] {
253
+ .stk-table.virtual-x .stk-table-main .virtual-x-left {
245
254
  padding: 0;
246
255
  }
@@ -0,0 +1,28 @@
1
+ export default class DragResize {
2
+ /**
3
+ *
4
+ * @param {HTMLElement} el
5
+ */
6
+ constructor(el: HTMLElement);
7
+ buttonSize: {
8
+ width: number;
9
+ height: number;
10
+ };
11
+ /** @type {ResizeObserver} */
12
+ resizeObserver: ResizeObserver;
13
+ /** @type {DOMRect} */
14
+ targetDOMRect: DOMRect;
15
+ /** @type {{left:number,top:number}} */
16
+ resizeButtonStyle: {
17
+ left: number;
18
+ top: number;
19
+ };
20
+ el: HTMLElement;
21
+ initData(): void;
22
+ createResizeButton(): void;
23
+ resizeButton: HTMLElement | undefined;
24
+ /** 监听元素大小改变 */
25
+ onResize(): void;
26
+ addButtonHoverStyle(): void;
27
+ addEvent(): void;
28
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * createElement function
3
+ * h(tag[, text[,children]])
4
+ * h(tag[, attrs[,children]])
5
+ * h(tag[, children])
6
+ * @param {String} tag 标签名称,支持tag#id.class emmet写法,暂支持id ,class
7
+ * @param {Object | String | Number | Array<HTMLElement>} attrs 传Object为属性,传String为textContent,传数组为children
8
+ * @param {Array<HTMLElement>} children
9
+ */
10
+ export default function h(tag: string, attrs: Object | string | number | Array<HTMLElement>, children: Array<HTMLElement>): HTMLElement;
package/package.json CHANGED
@@ -1,60 +1,60 @@
1
- {
2
- "name": "stk-table-vue",
3
- "version": "0.0.1-beta.4",
4
- "description": "simple realtime virtual table for vue3",
5
- "main": "./lib/stk-table-vue.js",
6
- "types": "./lib/StkTable/index.d.ts",
7
- "packageManager": "pnpm@8.11.0",
8
- "directories": {
9
- "test": "test"
10
- },
11
- "type": "module",
12
- "scripts": {
13
- "dev": "vite",
14
- "build": "vite build",
15
- "test": "vitest"
16
- },
17
- "keywords": [
18
- "virtual table",
19
- "vue",
20
- "highlight",
21
- "sticky"
22
- ],
23
- "files": [
24
- "lib",
25
- "src"
26
- ],
27
- "author": "japlus",
28
- "repository": {
29
- "type": "git",
30
- "url": "https://gitee.com/japlus/stk-table-vue"
31
- },
32
- "license": "MIT",
33
- "devDependencies": {
34
- "@types/d3-interpolate": "^3.0.4",
35
- "@typescript-eslint/eslint-plugin": "^6.14.0",
36
- "@typescript-eslint/parser": "^6.14.0",
37
- "@vitejs/plugin-vue": "^4.5.0",
38
- "@vitejs/plugin-vue-jsx": "^3.1.0",
39
- "@vue/test-utils": "2.4.0-alpha.2",
40
- "eslint": "^8.55.0",
41
- "eslint-config-prettier": "^9.1.0",
42
- "eslint-plugin-html": "^7.1.0",
43
- "eslint-plugin-prettier": "^5.0.1",
44
- "eslint-plugin-vue": "^9.19.2",
45
- "happy-dom": "^12.10.3",
46
- "less": "^4.2.0",
47
- "prettier": "^3.1.1",
48
- "pug": "^3.0.2",
49
- "typescript": "^5.3.3",
50
- "vite": "^5.0.6",
51
- "vite-plugin-dts": "^3.6.4",
52
- "vitest": "^1.1.0",
53
- "vue": "^3.3.9",
54
- "vue-eslint-parser": "^9.3.2",
55
- "vue-loader": "^17.2.2"
56
- },
57
- "dependencies": {
58
- "d3-interpolate": "^3.0.1"
59
- }
1
+ {
2
+ "name": "stk-table-vue",
3
+ "version": "0.0.1-beta.6",
4
+ "description": "simple realtime virtual table for vue3",
5
+ "main": "./lib/stk-table-vue.js",
6
+ "types": "./lib/StkTable/index.d.ts",
7
+ "packageManager": "pnpm@8.11.0",
8
+ "directories": {
9
+ "test": "test"
10
+ },
11
+ "type": "module",
12
+ "scripts": {
13
+ "dev": "vite",
14
+ "build": "vite build",
15
+ "test": "vitest"
16
+ },
17
+ "keywords": [
18
+ "virtual table",
19
+ "vue",
20
+ "highlight",
21
+ "sticky"
22
+ ],
23
+ "files": [
24
+ "lib",
25
+ "src"
26
+ ],
27
+ "author": "japlus",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://gitee.com/japlus/stk-table-vue"
31
+ },
32
+ "license": "MIT",
33
+ "devDependencies": {
34
+ "@types/d3-interpolate": "^3.0.4",
35
+ "@typescript-eslint/eslint-plugin": "^6.14.0",
36
+ "@typescript-eslint/parser": "^6.14.0",
37
+ "@vitejs/plugin-vue": "^4.5.0",
38
+ "@vitejs/plugin-vue-jsx": "^3.1.0",
39
+ "@vue/test-utils": "2.4.0-alpha.2",
40
+ "eslint": "^8.55.0",
41
+ "eslint-config-prettier": "^9.1.0",
42
+ "eslint-plugin-html": "^7.1.0",
43
+ "eslint-plugin-prettier": "^5.0.1",
44
+ "eslint-plugin-vue": "^9.19.2",
45
+ "happy-dom": "^12.10.3",
46
+ "less": "^4.2.0",
47
+ "prettier": "^3.1.1",
48
+ "pug": "^3.0.2",
49
+ "typescript": "^5.3.3",
50
+ "vite": "^5.0.6",
51
+ "vite-plugin-dts": "^3.6.4",
52
+ "vitest": "^1.1.0",
53
+ "vue": "^3.3.9",
54
+ "vue-eslint-parser": "^9.3.2",
55
+ "vue-loader": "^17.2.2"
56
+ },
57
+ "dependencies": {
58
+ "d3-interpolate": "^3.0.1"
59
+ }
60
60
  }
@@ -66,6 +66,7 @@
66
66
  showHeaderOverflow ? 'text-overflow' : '',
67
67
  col.headerClassName,
68
68
  col.fixed ? 'fixed-cell' : '',
69
+ col.fixed ? 'fixed-cell--' + col.fixed : '',
69
70
  ]"
70
71
  @click="
71
72
  e => {
@@ -161,7 +162,12 @@
161
162
  v-for="col in virtualX_columnPart"
162
163
  :key="col.dataIndex"
163
164
  :data-index="col.dataIndex"
164
- :class="[col.className, showOverflow ? 'text-overflow' : '', col.fixed ? 'fixed-cell' : '']"
165
+ :class="[
166
+ col.className,
167
+ showOverflow ? 'text-overflow' : '',
168
+ col.fixed ? 'fixed-cell' : '',
169
+ col.fixed ? 'fixed-cell--' + col.fixed : '',
170
+ ]"
165
171
  :style="getCellStyle(2, col)"
166
172
  @click="e => onCellClick(e, row, col)"
167
173
  >
@@ -189,9 +195,10 @@
189
195
  * [] 计算的高亮颜色,挂在数据源上对象上,若多个表格使用同一个数据源对象会有问题。需要深拷贝。(解决方案:获取组件uid)
190
196
  * [] highlight-row 颜色不能恢复到active的颜色
191
197
  */
192
- import { Order, SortOption, StkProps, StkTableColumn } from '@/StkTable/types/index';
193
198
  import { CSSProperties, computed, onMounted, ref, shallowRef, toRaw, watch } from 'vue';
194
199
  import { Default_Col_Width, Is_Legacy_Mode } from './const';
200
+ import { Order, SortOption, StkProps, StkTableColumn } from './types/index';
201
+ import { useAutoResize } from './useAutoResize';
195
202
  import { useColResize } from './useColResize';
196
203
  import { useHighlight } from './useHighlight';
197
204
  import { useThDrag } from './useThDrag';
@@ -223,6 +230,7 @@ const props = withDefaults(defineProps<StkProps>(), {
223
230
  colResizable: false,
224
231
  colMinWidth: 10,
225
232
  bordered: true,
233
+ autoResize: true,
226
234
  });
227
235
 
228
236
  const emit = defineEmits([
@@ -283,15 +291,20 @@ const fixedColumnsPositionStore = computed(() => {
283
291
  const store: Record<string, number> = {};
284
292
  const cols = [...tableHeaderLast.value];
285
293
  let left = 0;
294
+ /**遍历右侧fixed时,因为left已经遍历过一次了。所以,可以拿到right遍历边界 */
295
+ let rightStartIndex = 0;
286
296
  for (let i = 0; i < cols.length; i++) {
287
297
  const item = cols[i];
288
298
  if (item.fixed === 'left') {
289
299
  store[item.dataIndex] = left;
290
300
  left += parseInt(item.width || Default_Col_Width);
291
301
  }
302
+ if (!rightStartIndex && item.fixed === 'right') {
303
+ rightStartIndex = i;
304
+ }
292
305
  }
293
306
  let right = 0;
294
- for (let i = cols.length - 1; i >= 0; i--) {
307
+ for (let i = cols.length - 1; i >= rightStartIndex; i--) {
295
308
  const item = cols[i];
296
309
  if (item.fixed === 'right') {
297
310
  store[item.dataIndex] = right;
@@ -333,6 +346,10 @@ const {
333
346
  */
334
347
  const { setHighlightDimCell, setHighlightDimRow } = useHighlight({ props, tableContainer, rowKeyGen });
335
348
 
349
+ if (props.autoResize) {
350
+ useAutoResize({ tableContainer, initVirtualScroll, scrollTo, props, debounceMs: 500 });
351
+ }
352
+
336
353
  watch(
337
354
  () => props.columns,
338
355
  () => {
@@ -346,6 +363,10 @@ dealColumns();
346
363
  watch(
347
364
  () => props.dataSource,
348
365
  val => {
366
+ if (!val) {
367
+ console.warn('invalid dataSource');
368
+ return;
369
+ }
349
370
  // dealColumns(val);
350
371
  let needInitVirtualScrollY = false;
351
372
  if (dataSourceCopy.value.length !== val.length) {
@@ -694,9 +715,13 @@ function getTableData() {
694
715
  }
695
716
 
696
717
  defineExpose({
718
+ initVirtualScroll,
719
+ initVirtualScrollX,
720
+ initVirtualScrollY,
697
721
  setCurrentRow,
698
722
  setHighlightDimCell,
699
723
  setHighlightDimRow,
724
+ sortCol,
700
725
  setSorter,
701
726
  resetSorter,
702
727
  scrollTo,
@@ -704,7 +729,7 @@ defineExpose({
704
729
  });
705
730
  </script>
706
731
 
707
- <style lang="less" scoped>
732
+ <style lang="less">
708
733
  .stk-table {
709
734
  // contain: strict;
710
735
  --row-height: 28px;
@@ -846,6 +871,8 @@ defineExpose({
846
871
  .stk-table-main {
847
872
  border-spacing: 0;
848
873
  border-collapse: separate;
874
+ width: fit-content; // 用于兼容低版本,低版本width超过100%的时候还是100%,导致sticky错误。
875
+ min-width: 100%; // 用于兼容低版本chrome。低版本min-width 是min-content;
849
876
  &.fixed-mode {
850
877
  table-layout: fixed;
851
878
  }
@@ -896,7 +923,7 @@ defineExpose({
896
923
  }
897
924
 
898
925
  &.sorter-desc .table-header-cell-wrapper .table-header-sorter {
899
- // display:initial;
926
+ display: initial;
900
927
  #arrow-up {
901
928
  fill: var(--sort-arrow-active-sub-color);
902
929
  }
@@ -907,7 +934,7 @@ defineExpose({
907
934
  }
908
935
 
909
936
  &.sorter-asc .table-header-cell-wrapper .table-header-sorter {
910
- // display:initial;
937
+ display: initial;
911
938
  #arrow-up {
912
939
  fill: var(--sort-arrow-active-color);
913
940
  }
@@ -932,8 +959,7 @@ defineExpose({
932
959
  margin-left: 4px;
933
960
  width: 16px;
934
961
  height: 16px;
935
-
936
- // display:none;
962
+ display: none;
937
963
  #arrow-up,
938
964
  #arrow-down {
939
965
  fill: var(--sort-arrow-color);
@@ -1,2 +1,3 @@
1
1
  export { default as StkTable } from './StkTable.vue';
2
2
  export { tableSort, insertToOrderedArray } from './utils';
3
+ export type { StkTableColumn } from './types/index';
@@ -140,4 +140,10 @@ export type StkProps = Partial<{
140
140
  * "body-v" - 仅表体展示竖线
141
141
  */
142
142
  bordered: boolean | 'h' | 'v' | 'body-v';
143
+
144
+ /**
145
+ * 自动重新计算虚拟滚动高度宽度。默认true
146
+ * [非响应式]
147
+ */
148
+ autoResize: boolean;
143
149
  }>;
@@ -0,0 +1,67 @@
1
+ import { Ref, onBeforeUnmount, onMounted, watch } from 'vue';
2
+
3
+ type Options = {
4
+ tableContainer: Ref<HTMLElement | undefined>;
5
+ initVirtualScroll: () => void;
6
+ scrollTo: () => void;
7
+ props: any;
8
+ /** 防抖延时 */
9
+ debounceMs: number;
10
+ };
11
+ /**
12
+ * 窗口变化自动重置虚拟滚动
13
+ * @param param0
14
+ */
15
+ export function useAutoResize({ tableContainer, initVirtualScroll, scrollTo, props, debounceMs }: Options) {
16
+ let resizeObserver: ResizeObserver | null = null;
17
+
18
+ onMounted(() => {
19
+ initResizeObserver();
20
+ });
21
+
22
+ onBeforeUnmount(() => {
23
+ removeResizeObserver();
24
+ });
25
+
26
+ function initResizeObserver() {
27
+ if (window.ResizeObserver) {
28
+ if (!tableContainer.value) {
29
+ const watchDom = watch(
30
+ () => tableContainer,
31
+ () => {
32
+ initResizeObserver();
33
+ watchDom();
34
+ },
35
+ );
36
+ return;
37
+ }
38
+ resizeObserver = new ResizeObserver(resizeCallback);
39
+ resizeObserver.observe(tableContainer.value);
40
+ } else {
41
+ window.addEventListener('resize', resizeCallback);
42
+ }
43
+ }
44
+
45
+ function removeResizeObserver() {
46
+ if (resizeObserver) {
47
+ resizeObserver.disconnect();
48
+ resizeObserver = null;
49
+ } else {
50
+ window.removeEventListener('resize', resizeCallback);
51
+ }
52
+ }
53
+
54
+ let debounceTime = 0;
55
+ function resizeCallback() {
56
+ if (debounceTime) {
57
+ window.clearTimeout(debounceTime);
58
+ }
59
+ debounceTime = window.setTimeout(() => {
60
+ if (props.autoResize) {
61
+ scrollTo();
62
+ initVirtualScroll();
63
+ }
64
+ debounceTime = 0;
65
+ }, debounceMs);
66
+ }
67
+ }
@@ -91,29 +91,18 @@ export function useVirtualScroll({ tableContainer, props, dataSourceCopy, tableH
91
91
  * @param {number} [height] 虚拟滚动的高度
92
92
  */
93
93
  function initVirtualScrollY(height?: number) {
94
- if (virtual_on.value) {
95
- virtualScroll.value.containerHeight = typeof height === 'number' ? height : tableContainer.value?.offsetHeight || Default_Table_Height;
96
- updateVirtualScrollY(tableContainer.value?.scrollTop);
97
- // const { offsetTop, containerHeight, rowHeight } = virtualScroll.value;
98
- // const tableAllHeight = dataSourceCopy.value.length * rowHeight;
99
- // const overflowHeight = tableAllHeight - containerHeight;
100
- // if (overflowHeight < offsetTop && overflowHeight > 0) {
101
- // virtualScroll.value.offsetTop = overflowHeight;
102
- // virtualScroll.value.startIndex = Math.ceil(overflowHeight / rowHeight);
103
- // } else if (overflowHeight <= 0) {
104
- // virtualScroll.value.offsetTop = 0;
105
- // virtualScroll.value.startIndex = 0;
106
- // }
107
- }
94
+ if (!virtual_on.value) return;
95
+ // FIXME: 可能多次获取offsetHeight 会导致浏览器频繁重排
96
+ virtualScroll.value.containerHeight = typeof height === 'number' ? height : tableContainer.value?.offsetHeight || Default_Table_Height;
97
+ updateVirtualScrollY(tableContainer.value?.scrollTop);
108
98
  }
109
99
 
110
100
  function initVirtualScrollX() {
111
- if (props.virtualX) {
112
- const { offsetWidth, scrollLeft } = tableContainer.value || {};
113
- // scrollTo(null, 0);
114
- virtualScrollX.value.containerWidth = offsetWidth || Default_Table_Width;
115
- updateVirtualScrollX(scrollLeft);
116
- }
101
+ if (!props.virtualX) return;
102
+ const { offsetWidth, scrollLeft } = tableContainer.value || {};
103
+ // scrollTo(null, 0);
104
+ virtualScrollX.value.containerWidth = offsetWidth || Default_Table_Width;
105
+ updateVirtualScrollX(scrollLeft);
117
106
  }
118
107
 
119
108
  /** 通过滚动条位置,计算虚拟滚动的参数 */
@@ -72,6 +72,7 @@ function strCompare(a: string, b: string, type: 'number' | 'string'): number {
72
72
  * @param dataSource 排序的数组
73
73
  */
74
74
  export function tableSort(sortOption: SortOption, order: Order, dataSource: any[]): any[] {
75
+ if (!dataSource?.length) return dataSource || [];
75
76
  let targetDataSource = [...dataSource];
76
77
  if (typeof sortOption.sorter === 'function') {
77
78
  const customSorterData = sortOption.sorter(targetDataSource, { order, column: sortOption });