stk-table-vue 0.2.0 → 0.2.1

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.
@@ -1,10 +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;
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,7 +1,7 @@
1
1
  {
2
2
  "name": "stk-table-vue",
3
- "version": "0.2.0",
4
- "description": "simple realtime virtual table for vue3",
3
+ "version": "0.2.1",
4
+ "description": "Simple realtime virtual table for vue3&vue2.7",
5
5
  "main": "./lib/stk-table-vue.js",
6
6
  "types": "./lib/StkTable/index.d.ts",
7
7
  "packageManager": "pnpm@8.14.3",
@@ -57,7 +57,7 @@
57
57
  v-for="(col, colIndex) in virtualX_on && rowIndex === tableHeaders.length - 1 ? virtualX_columnPart : row"
58
58
  :key="col.dataIndex"
59
59
  :data-col-key="colKeyGen(col)"
60
- :draggable="headerDrag ? 'true' : 'false'"
60
+ :draggable="isHeaderDraggable(col) ? 'true' : 'false'"
61
61
  :rowspan="virtualX_on ? 1 : col.rowSpan"
62
62
  :colspan="col.colSpan"
63
63
  :style="getCellStyle(1, col, rowIndex)"
@@ -180,7 +180,7 @@
180
180
  </div>
181
181
  </template>
182
182
 
183
- <script setup lang="tsx">
183
+ <script setup lang="ts">
184
184
  /**
185
185
  * @author JA+
186
186
  * 不支持低版本浏览器非虚拟滚动表格的表头固定,列固定,因为会卡。
@@ -191,7 +191,7 @@
191
191
  */
192
192
  import { CSSProperties, onMounted, ref, shallowRef, toRaw, watch } from 'vue';
193
193
  import { Default_Row_Height } from './const';
194
- import { Order, SortOption, StkTableColumn, UniqKey } from './types/index';
194
+ import { Order, SortOption, SortState, StkTableColumn, UniqKey } from './types/index';
195
195
  import { useAutoResize } from './useAutoResize';
196
196
  import { useColResize } from './useColResize';
197
197
  import { useFixedCol } from './useFixedCol';
@@ -252,8 +252,8 @@ const props = withDefaults(
252
252
  showOverflow?: boolean;
253
253
  /** 是否增加行hover class */
254
254
  showTrHoverClass?: boolean;
255
- /** 表头是否可拖动 */
256
- headerDrag?: boolean;
255
+ /** 表头是否可拖动。支持回调函数。 */
256
+ headerDrag?: boolean | ((col: StkTableColumn<DT>) => boolean);
257
257
  /**
258
258
  * 给行附加className<br>
259
259
  * FIXME: 是否需要优化,因为不传此prop会使表格行一直执行空函数,是否有影响
@@ -449,7 +449,7 @@ const { isColResizing, onThResizeMouseDown } = useColResize({
449
449
  tableHeaderLast,
450
450
  });
451
451
 
452
- const { onThDragStart, onThDragOver, onThDrop } = useThDrag({ emits });
452
+ const { onThDragStart, onThDragOver, onThDrop, isHeaderDraggable } = useThDrag({ props, emits });
453
453
 
454
454
  const {
455
455
  virtualScroll,
@@ -482,7 +482,7 @@ const { getFixedStyle } = useFixedStyle({
482
482
  const { setHighlightDimCell, setHighlightDimRow } = useHighlight({ props, tableContainer, rowKeyGen });
483
483
 
484
484
  if (props.autoResize) {
485
- useAutoResize({ tableContainer, initVirtualScroll, scrollTo, props, debounceMs: 500 });
485
+ useAutoResize({ tableContainer, initVirtualScroll, props, debounceMs: 200 });
486
486
  }
487
487
 
488
488
  /** 键盘箭头滚动 */
@@ -627,7 +627,7 @@ function rowKeyGen(row: DT) {
627
627
  * 列唯一键
628
628
  * @param col
629
629
  */
630
- function colKeyGen(col: StkTableColumn<any>) {
630
+ function colKeyGen(col: StkTableColumn<DT>) {
631
631
  return typeof props.colKey === 'function' ? props.colKey(col) : (col as any)[props.colKey];
632
632
  }
633
633
 
@@ -769,6 +769,9 @@ function onTableScroll(e: Event) {
769
769
  updateFixedShadow();
770
770
  if (virtualX_on.value) {
771
771
  updateVirtualScrollX(scrollLeft);
772
+ } else {
773
+ // 非虚拟滚动也记录一下滚动条位置。用于判断isXScroll
774
+ virtualScrollX.value.scrollLeft = scrollLeft;
772
775
  }
773
776
  }
774
777
 
@@ -848,6 +851,13 @@ function getTableData() {
848
851
  return toRaw(dataSourceCopy.value);
849
852
  }
850
853
 
854
+ /** 获取当前排序列的信息 */
855
+ function getSortColumns(): SortState<DT>[] {
856
+ const sortOrder = sortSwitchOrder[sortOrderIndex.value];
857
+ if (!sortOrder) return [];
858
+ return [{ dataIndex: sortCol.value, order: sortOrder }];
859
+ }
860
+
851
861
  defineExpose({
852
862
  /** 初始化横向纵向虚拟滚动 */
853
863
  initVirtualScroll,
@@ -863,6 +873,8 @@ defineExpose({
863
873
  setHighlightDimRow,
864
874
  /** 表格排序列dataIndex */
865
875
  sortCol,
876
+ /** 获取当前排序状态 */
877
+ getSortColumns,
866
878
  /** 设置排序 */
867
879
  setSorter,
868
880
  /** 重置排序 */
@@ -1,5 +1,5 @@
1
1
  /**高亮渐暗 */
2
- @keyframes stkTableDim {
2
+ @keyframes stk-table-dim {
3
3
  from {
4
4
  background-color: var(--highlight-color);
5
5
  }
@@ -41,9 +41,11 @@
41
41
  overflow: auto;
42
42
  display: flex;
43
43
  flex-direction: column;
44
+ box-sizing: border-box;
44
45
  /* border-left: 此方案用于减少cell 中border-left 的css选择。同时利于多级表头border-left问题。利于横向滚动border-left*/
45
46
  border-left: 1px solid var(--border-color);
46
-
47
+ /* 下面border用于表格内容不满高度时,绘制表格边界线 */
48
+ background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
47
49
  /**深色模式 */
48
50
  &.dark {
49
51
  --th-bgc: #202029;
@@ -75,6 +77,7 @@
75
77
 
76
78
  &.headless {
77
79
  border-top: 1px solid var(--border-color);
80
+ background-image: var(--bg-border-right), var(--bg-border-bottom);
78
81
  }
79
82
 
80
83
  /* 调整列宽的话,表格宽度应当自适应 */
@@ -112,7 +115,6 @@
112
115
  tr {
113
116
  &:first-child th {
114
117
  background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
115
-
116
118
  }
117
119
 
118
120
  }
@@ -209,7 +211,7 @@
209
211
  }
210
212
 
211
213
  &.highlight-cell {
212
- animation: stkTableDim 2s linear;
214
+ animation: stk-table-dim 2s linear;
213
215
  }
214
216
 
215
217
  &.text-overflow {
@@ -349,7 +351,7 @@
349
351
 
350
352
  /* td inherit tr bgc*/
351
353
  &.highlight-row {
352
- animation: stkTableDim 2s linear;
354
+ animation: stk-table-dim 2s linear;
353
355
  }
354
356
 
355
357
  /* &.highlight-row-transition {
@@ -21,11 +21,11 @@ export type StkTableColumn<T extends Record<string, any>> = {
21
21
  /** 筛选 */
22
22
  sorter?: Sorter<T>;
23
23
  /** 列宽。横向虚拟滚动时必须设置。 */
24
- width?: string;
24
+ width?: string | number;
25
25
  /** 最小列宽。非x虚拟滚动生效。 */
26
- minWidth?: string;
26
+ minWidth?: string | number;
27
27
  /** 最大列宽。非x虚拟滚动生效。 */
28
- maxWidth?: string;
28
+ maxWidth?: string | number;
29
29
  /**th class */
30
30
  headerClassName?: string;
31
31
  /** td class */
@@ -1,10 +1,9 @@
1
1
  import { Ref, onBeforeUnmount, onMounted, watch } from 'vue';
2
2
 
3
3
  type Options = {
4
+ props: any;
4
5
  tableContainer: Ref<HTMLElement | undefined>;
5
6
  initVirtualScroll: () => void;
6
- scrollTo: () => void;
7
- props: any;
8
7
  /** 防抖延时 */
9
8
  debounceMs: number;
10
9
  };
@@ -12,7 +11,7 @@ type Options = {
12
11
  * 窗口变化自动重置虚拟滚动
13
12
  * @param param0
14
13
  */
15
- export function useAutoResize({ tableContainer, initVirtualScroll, scrollTo, props, debounceMs }: Options) {
14
+ export function useAutoResize({ tableContainer, initVirtualScroll, props, debounceMs }: Options) {
16
15
  let resizeObserver: ResizeObserver | null = null;
17
16
 
18
17
  onMounted(() => {
@@ -1,6 +1,6 @@
1
1
  import { Ref, onBeforeUnmount, onMounted, ref } from 'vue';
2
- import { Default_Col_Width } from './const';
3
2
  import { StkTableColumn } from './types';
3
+ import { getColWidth } from './utils';
4
4
 
5
5
  type ColResizeState<DT extends Record<string, any>> = {
6
6
  /** 当前被拖动的列*/
@@ -115,7 +115,7 @@ export function useColResize<DT extends Record<string, any>>({
115
115
  const { lastCol, startX, startOffsetTableX } = colResizeState;
116
116
  const { clientX } = e;
117
117
  let moveX = clientX - startX;
118
- const currentColWidth = parseInt(lastCol?.width || Default_Col_Width);
118
+ const currentColWidth = getColWidth(lastCol);
119
119
  // 移动量不小于最小列宽
120
120
  if (currentColWidth + moveX < props.colMinWidth) {
121
121
  moveX = -currentColWidth;
@@ -136,7 +136,7 @@ export function useColResize<DT extends Record<string, any>>({
136
136
  const moveX = clientX - startX;
137
137
 
138
138
  // 移动量不小于最小列宽
139
- let width = parseInt(lastCol?.width || Default_Col_Width) + moveX;
139
+ let width = getColWidth(lastCol) + moveX;
140
140
  if (width < props.colMinWidth) width = props.colMinWidth;
141
141
 
142
142
  const curCol = tableHeaderLast.value.find(it => colKeyGen(it) === colKeyGen(lastCol));
@@ -31,7 +31,7 @@ export function useFixedCol<DT extends Record<string, any>>({ props, tableHeader
31
31
  fixedShadowCols = [];
32
32
  // 找到最右边的固定列 findLast
33
33
  let lastLeftCol = null;
34
- for (let i = tableHeaderLast.value.length - 1; i > 0; i--) {
34
+ for (let i = tableHeaderLast.value.length - 1; i >= 0; i--) {
35
35
  const col = tableHeaderLast.value[i];
36
36
  if (col.fixed === 'left') {
37
37
  lastLeftCol = col;
@@ -1,7 +1,8 @@
1
1
  import { CSSProperties, Ref, computed } from 'vue';
2
- import { Default_Col_Width, Is_Legacy_Mode } from './const';
2
+ import { Is_Legacy_Mode } from './const';
3
3
  import { StkTableColumn } from './types';
4
4
  import { VirtualScrollStore, VirtualScrollXStore } from './useVirtualScroll';
5
+ import { getColWidth } from './utils';
5
6
 
6
7
  type Options = {
7
8
  props: any;
@@ -27,7 +28,7 @@ export function useFixedStyle({ props, tableHeaderLast, virtualScroll, virtualSc
27
28
  const item = cols[i];
28
29
  if (item.fixed === 'left') {
29
30
  store[item.dataIndex] = left;
30
- left += parseInt(item.width || Default_Col_Width);
31
+ left += getColWidth(item);
31
32
  }
32
33
  if (!rightStartIndex && item.fixed === 'right') {
33
34
  rightStartIndex = i;
@@ -38,7 +39,7 @@ export function useFixedStyle({ props, tableHeaderLast, virtualScroll, virtualSc
38
39
  const item = cols[i];
39
40
  if (item.fixed === 'right') {
40
41
  store[item.dataIndex] = right;
41
- right += parseInt(item.width || Default_Col_Width);
42
+ right += getColWidth(item);
42
43
  }
43
44
  }
44
45
 
@@ -47,6 +47,7 @@ export function useHighlight({ props, tableContainer, rowKeyGen }: Params) {
47
47
  // void rowEl.offsetHeight; // reflow
48
48
  // rowEl.classList.add('highlight-row-transition');
49
49
  // }
50
+
50
51
  /** 经过的时间 ÷ 高亮持续时间 计算出 颜色过渡进度 (0-1) */
51
52
  const progress = (nowTs - row._bgc_progress_ms) / Highlight_Duration;
52
53
  // row._bgc_progress = progress;
@@ -58,6 +59,7 @@ export function useHighlight({ props, tableContainer, rowKeyGen }: Params) {
58
59
  }
59
60
  });
60
61
  needDeleteRows.forEach((row: any) => highlightDimRows.delete(row));
62
+ // TODO: shallowRef 时,需要手动更新
61
63
 
62
64
  if (highlightDimRows.size > 0) {
63
65
  // 还有高亮的行,则下一次循环
@@ -1,4 +1,7 @@
1
+ import { StkTableColumn } from './types';
2
+
1
3
  type Params = {
4
+ props: any;
2
5
  emits: any;
3
6
  };
4
7
  /**
@@ -6,28 +9,43 @@ type Params = {
6
9
  * @param param0
7
10
  * @returns
8
11
  */
9
- export function useThDrag({ emits }: Params) {
12
+ export function useThDrag<DT extends Record<string, any>>({ props, emits }: Params) {
10
13
  let dragStartKey: string | undefined = void 0;
11
14
 
15
+ function findParentTH(el: HTMLElement | Node) {
16
+ let n: any = el;
17
+ while (n) {
18
+ if (n.tagName === 'TH') return n;
19
+ n = n.parentElement;
20
+ }
21
+ }
12
22
  /** 开始拖动记录th位置 */
13
23
  function onThDragStart(e: MouseEvent) {
14
24
  // const i = Array.prototype.indexOf.call(e.target.parentNode.children, e.target); // 得到是第几个子元素
15
- dragStartKey = (e.target as HTMLElement).dataset.colKey;
25
+ const th = findParentTH(e.target as HTMLElement | Node);
26
+ if (!th) return;
27
+
28
+ dragStartKey = th.dataset.colKey;
16
29
  emits('th-drag-start', dragStartKey);
17
30
  }
18
31
 
19
32
  function onThDragOver(e: MouseEvent) {
33
+ const th = findParentTH(e.target as HTMLElement | Node);
34
+ if (!th) return;
35
+
36
+ const isHeaderDraggable = th.getAttribute('draggable') === 'true';
37
+ if (!isHeaderDraggable) {
38
+ // 不可drag的表头不可被覆盖
39
+ return;
40
+ }
20
41
  e.preventDefault();
21
42
  }
22
43
 
23
44
  /** th拖动释放时 */
24
45
  function onThDrop(e: MouseEvent) {
25
- let th = e.target as HTMLElement;
26
- // 找到th元素
27
- while (th) {
28
- if (th.tagName === 'TH') break;
29
- th = th.parentNode as HTMLElement;
30
- }
46
+ const th = findParentTH(e.target as HTMLElement | Node);
47
+ if (!th) return;
48
+
31
49
  // const i = Array.prototype.indexOf.call(th.parentNode.children, th); // 得到是第几个子元素
32
50
  if (dragStartKey !== th.dataset.colKey) {
33
51
  emits('col-order-change', dragStartKey, th.dataset.colKey);
@@ -35,9 +53,20 @@ export function useThDrag({ emits }: Params) {
35
53
  emits('th-drop', th.dataset.colKey);
36
54
  }
37
55
 
56
+ const isHeaderDragFun = typeof props.headerDrag === 'function';
57
+ /** 是否可拖拽 */
58
+ function isHeaderDraggable(col: StkTableColumn<DT>) {
59
+ if (isHeaderDragFun) {
60
+ return props.headerDrag(col);
61
+ } else {
62
+ return props.headerDrag;
63
+ }
64
+ }
65
+
38
66
  return {
39
67
  onThDragStart,
40
68
  onThDragOver,
41
69
  onThDrop,
70
+ isHeaderDraggable,
42
71
  };
43
72
  }
@@ -1,6 +1,7 @@
1
1
  import { Ref, ShallowRef, computed, ref } from 'vue';
2
- import { Default_Col_Width, Default_Table_Height, Default_Table_Width } from './const';
2
+ import { Default_Table_Height, Default_Table_Width } from './const';
3
3
  import { StkTableColumn } from './types';
4
+ import { getColWidth } from './utils';
4
5
 
5
6
  type Option<DT extends Record<string, any>> = {
6
7
  tableContainer: Ref<HTMLElement | undefined>;
@@ -40,11 +41,6 @@ export type VirtualScrollXStore = {
40
41
  scrollLeft: number;
41
42
  };
42
43
 
43
- /**获取计算宽度 */
44
- function getCalcWidth<DT extends Record<string, any>>(col: StkTableColumn<DT>) {
45
- return parseInt(col.minWidth || col.width || Default_Col_Width);
46
- }
47
-
48
44
  /** vue2 优化滚动回收延时 */
49
45
  const VUE2_SCROLL_TIMEOUT_MS = 200;
50
46
 
@@ -90,9 +86,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({ props, tableC
90
86
  });
91
87
 
92
88
  const virtualX_on = computed(() => {
93
- return (
94
- props.virtualX && tableHeaderLast.value.reduce((sum, col) => (sum += getCalcWidth(col)), 0) > virtualScrollX.value.containerWidth + 100
95
- );
89
+ return props.virtualX && tableHeaderLast.value.reduce((sum, col) => (sum += getColWidth(col)), 0) > virtualScrollX.value.containerWidth + 100;
96
90
  });
97
91
 
98
92
  const virtualX_columnPart = computed(() => {
@@ -125,7 +119,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({ props, tableC
125
119
  for (let i = virtualScrollX.value.endIndex; i < tableHeaderLast.value.length; i++) {
126
120
  const col = tableHeaderLast.value[i];
127
121
  if (col.fixed !== 'right') {
128
- width += getCalcWidth(col);
122
+ width += getColWidth(col);
129
123
  }
130
124
  }
131
125
  return width;
@@ -219,7 +213,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({ props, tableC
219
213
  const col = tableHeaderLast.value[colIndex];
220
214
  // fixed left 不进入计算列宽
221
215
  if (col.fixed === 'left') continue;
222
- const colWidth = getCalcWidth(col);
216
+ const colWidth = getColWidth(col);
223
217
  colWidthSum += colWidth;
224
218
  // 列宽(非固定列)加到超过scrollLeft的时候,表示startIndex从上一个开始下标
225
219
  if (colWidthSum >= sLeft) {
@@ -233,7 +227,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({ props, tableC
233
227
  let endIndex = headerLength;
234
228
  for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {
235
229
  const col = tableHeaderLast.value[colIndex];
236
- colWidthSum += getCalcWidth(col);
230
+ colWidthSum += getColWidth(col);
237
231
  // 列宽大于容器宽度则停止
238
232
  if (colWidthSum >= virtualScrollX.value.containerWidth) {
239
233
  endIndex = colIndex + 1; // TODO:预渲染的列数
@@ -1,3 +1,4 @@
1
+ import { Default_Col_Width } from './const';
1
2
  import { Order, SortOption, SortState, StkTableColumn } from './types';
2
3
 
3
4
  /**
@@ -126,3 +127,11 @@ export function howDeepTheHeader(arr: StkTableColumn<any>[], level = 1) {
126
127
  });
127
128
  return Math.max(...levels);
128
129
  }
130
+
131
+ /** 获取列宽 */
132
+ export function getColWidth(col: StkTableColumn<any> | null): number {
133
+ if (typeof col?.width === 'number') {
134
+ return Math.floor(col.width ?? Default_Col_Width);
135
+ }
136
+ return parseInt(col?.width ?? Default_Col_Width);
137
+ }