stk-table-vue 0.8.7 → 0.8.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stk-table-vue",
3
- "version": "0.8.7",
3
+ "version": "0.8.8",
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",
@@ -59,15 +59,15 @@
59
59
  "postcss-discard-comments": "^6.0.2",
60
60
  "postcss-preset-env": "^9.5.11",
61
61
  "prettier": "^3.2.5",
62
- "stk-table-vue": "^0.8.1",
62
+ "stk-table-vue": "^0.8.7",
63
63
  "typescript": "^5.8.3",
64
- "vite": "^7.0.2",
64
+ "vite": "^7.1.7",
65
65
  "vite-plugin-dts": "3.9.1",
66
66
  "vitepress": "^1.6.4",
67
- "vitepress-demo-plugin": "^1.4.5",
67
+ "vitepress-demo-plugin": "^1.4.7",
68
68
  "vitepress-plugin-llms": "^1.7.5",
69
69
  "vitest": "^3.2.4",
70
- "vue": "^3.5.17",
70
+ "vue": "^3.5.22",
71
71
  "vue-eslint-parser": "^9.4.2"
72
72
  }
73
73
  }
@@ -253,7 +253,7 @@ import { CSSProperties, computed, nextTick, onMounted, ref, shallowRef, toRaw, w
253
253
  import DragHandle from './components/DragHandle.vue';
254
254
  import SortIcon from './components/SortIcon.vue';
255
255
  import TriangleIcon from './components/TriangleIcon.vue';
256
- import { CELL_KEY_SEPARATE, DEFAULT_ROW_HEIGHT, DEFAULT_SMOOTH_SCROLL, IS_LEGACY_MODE } from './const';
256
+ import { CELL_KEY_SEPARATE, DEFAULT_ROW_HEIGHT, DEFAULT_SMOOTH_SCROLL, DEFAULT_SORT_CONFIG, IS_LEGACY_MODE } from './const';
257
257
  import {
258
258
  AutoRowHeightConfig,
259
259
  ColResizableConfig,
@@ -473,10 +473,7 @@ const props = withDefaults(
473
473
  autoResize: true,
474
474
  fixedColShadow: false,
475
475
  optimizeVue2Scroll: false,
476
- sortConfig: () => ({
477
- emptyToBottom: false,
478
- stringLocaleCompare: false,
479
- }),
476
+ sortConfig: () => DEFAULT_SORT_CONFIG,
480
477
  hideHeaderTitle: false,
481
478
  highlightConfig: () => ({}),
482
479
  seqConfig: () => ({}),
@@ -749,7 +746,8 @@ const SRBRTotalHeight = computed(() => {
749
746
  });
750
747
  const SRBRBottomHeight = computed(() => {
751
748
  if (!isSRBRActive.value || !props.virtual) return 0;
752
- return (virtualScroll.value.containerHeight - tableHeaderHeight.value) % virtualScroll.value.rowHeight;
749
+ const { containerHeight, rowHeight } = virtualScroll.value;
750
+ return (containerHeight - tableHeaderHeight.value) % rowHeight;
753
751
  });
754
752
 
755
753
  const rowKeyGenCache = new WeakMap();
@@ -1131,8 +1129,8 @@ function onColumnSort(col: StkTableColumn<DT> | undefined | null, click = true,
1131
1129
  sortOrderIndex.value = sortOrderIndex.value % 3;
1132
1130
 
1133
1131
  let order = sortSwitchOrder[sortOrderIndex.value];
1134
- const sortConfig = { ...props.sortConfig, ...col.sortConfig };
1135
- const defaultSort = sortConfig.defaultSort;
1132
+ const sortConfig: SortConfig<any> = { ...DEFAULT_SORT_CONFIG, ...props.sortConfig, ...col.sortConfig };
1133
+ const { defaultSort } = sortConfig;
1136
1134
  const colKeyGenValue = colKeyGen.value;
1137
1135
 
1138
1136
  if (!order && defaultSort) {
@@ -1158,15 +1156,17 @@ function onColumnSort(col: StkTableColumn<DT> | undefined | null, click = true,
1158
1156
  }
1159
1157
  }
1160
1158
  }
1159
+ let dataSourceTemp: any[] = props.dataSource.slice();
1161
1160
  if (!props.sortRemote || options.force) {
1162
1161
  const sortOption = col || defaultSort;
1163
1162
  if (sortOption) {
1164
- dataSourceCopy.value = tableSort(sortOption, order, props.dataSource, sortConfig);
1163
+ dataSourceTemp = tableSort(sortOption, order, dataSourceTemp, sortConfig);
1164
+ dataSourceCopy.value = isTreeData.value ? flatTreeData(dataSourceTemp) : dataSourceTemp;
1165
1165
  }
1166
1166
  }
1167
- // 只有点击才触发事件
1167
+ // 只有点击才触发事件 en: only emit sort-change event when click
1168
1168
  if (click || options.emit) {
1169
- emits('sort-change', col, order, toRaw(dataSourceCopy.value), sortConfig);
1169
+ emits('sort-change', col, order, toRaw(dataSourceTemp), sortConfig);
1170
1170
  }
1171
1171
  }
1172
1172
 
@@ -1391,15 +1391,32 @@ function onTrMouseLeave(e: MouseEvent) {
1391
1391
  * 选中一行
1392
1392
  * @param {string} rowKeyOrRow selected rowKey, undefined to unselect
1393
1393
  * @param {boolean} option.silent if set true not emit `current-change`. default:false
1394
+ * @param {boolean} option.deep if set true, deep search in children. default:false
1394
1395
  */
1395
- function setCurrentRow(rowKeyOrRow: string | undefined | DT, option = { silent: false }) {
1396
+ function setCurrentRow(rowKeyOrRow: string | undefined | DT, option = { silent: false, deep: false }) {
1396
1397
  if (!dataSourceCopy.value.length) return;
1397
1398
  const select = rowKeyOrRow !== void 0;
1398
1399
  if (!select) {
1399
1400
  currentRow.value = void 0;
1400
1401
  currentRowKey.value = void 0;
1401
1402
  } else if (typeof rowKeyOrRow === 'string') {
1402
- const row = dataSourceCopy.value.find(it => rowKeyGen(it) === rowKeyOrRow);
1403
+ const findRowByKey = (data: DT[], key: string): DT | null => {
1404
+ for (let i = 0; i < data.length; i++) {
1405
+ const item = data[i];
1406
+ if (rowKeyGen(item) === key) {
1407
+ return item;
1408
+ }
1409
+ if (option.deep && item.children?.length) {
1410
+ const found = findRowByKey(item.children, key);
1411
+ if (found) {
1412
+ return found;
1413
+ }
1414
+ }
1415
+ }
1416
+ return null;
1417
+ };
1418
+
1419
+ const row = findRowByKey(dataSourceCopy.value, rowKeyOrRow);
1403
1420
  if (!row) {
1404
1421
  console.warn('setCurrentRow failed.rowKey:', rowKeyOrRow);
1405
1422
  return;
@@ -1447,7 +1464,6 @@ function setSorter(colKey: string, order: Order, option: { sortOption?: SortOpti
1447
1464
  const colKeyGenValue = colKeyGen.value;
1448
1465
 
1449
1466
  if (newOption.sort && dataSourceCopy.value?.length) {
1450
- // 如果表格有数据,则进行排序
1451
1467
  const column = newOption.sortOption || tableHeaderLast.value.find(it => colKeyGenValue(it) === sortCol.value);
1452
1468
  if (column) onColumnSort(column, false, { force: option.force ?? true, emit: !newOption.silent });
1453
1469
  else console.warn('Can not find column by key:', sortCol.value);
@@ -1,3 +1,4 @@
1
+ import { SortConfig } from './types';
1
2
  import { getBrowsersVersion } from './utils';
2
3
 
3
4
  export const DEFAULT_COL_WIDTH = '100';
@@ -33,5 +34,11 @@ export const STK_ID_PREFIX = 'stk';
33
34
  /** expanded row key prefix */
34
35
  export const EXPANDED_ROW_KEY_PREFIX = 'expanded-';
35
36
 
36
- /** cell key 的分隔符 */
37
+ /** cell key split str */
37
38
  export const CELL_KEY_SEPARATE = '--';
39
+
40
+ export const DEFAULT_SORT_CONFIG = {
41
+ emptyToBottom: false,
42
+ stringLocaleCompare: false,
43
+ sortChildren: false,
44
+ } satisfies SortConfig<any>;
@@ -88,7 +88,7 @@ export type StkTableColumn<T extends Record<string, any>> = {
88
88
  /** 排序方式。按数字/字符串 */
89
89
  sortType?: 'number' | 'string';
90
90
  /** 配置当前列的排序规则 */
91
- sortConfig?: Pick<SortConfig<T>, 'emptyToBottom' | 'stringLocaleCompare'>;
91
+ sortConfig?: Omit<SortConfig<T>, 'defaultSort'>;
92
92
  /** 固定列 */
93
93
  fixed?: 'left' | 'right' | null;
94
94
  /**
@@ -176,17 +176,17 @@ export type UniqKeyFun = (param: any) => UniqKey;
176
176
  export type UniqKeyProp = UniqKey | UniqKeyFun;
177
177
 
178
178
  export type SortConfig<T extends Record<string, any>> = {
179
- /** 空值始终排在列表末尾 */
180
- emptyToBottom?: boolean;
181
179
  /**
182
- * 默认排序(1.初始化时触发 2.排序方向为null时触发)
183
- * 类似onMounted时,调用setSorter点了下表头。
180
+ * 1. trigger when init
181
+ * 2. trigger when sort direction is null
184
182
  */
185
183
  defaultSort?: {
186
184
  /**
187
- * 列唯一键,
185
+ * colKey
186
+ *
187
+ * if set `props.colKey`
188
188
  *
189
- * 如果您配了 `props.colKey` 则这里表示的列唯一键的值
189
+ * default: StkTableColumn<T>['dataIndex']
190
190
  */
191
191
  key?: StkTableColumn<T>['key'];
192
192
  dataIndex: StkTableColumn<T>['dataIndex'];
@@ -194,14 +194,22 @@ export type SortConfig<T extends Record<string, any>> = {
194
194
  sortField?: StkTableColumn<T>['sortField'];
195
195
  sortType?: StkTableColumn<T>['sortType'];
196
196
  sorter?: StkTableColumn<T>['sorter'];
197
- /** 是否禁止触发sort-change事件。默认false,表示触发事件。 */
197
+ /**
198
+ * whether to disable trigger`sort-change` event. default: false
199
+ */
198
200
  silent?: boolean;
199
201
  };
202
+ /** empty value always sort to bottom */
203
+ emptyToBottom?: boolean;
200
204
  /**
201
205
  * string sort if use `String.prototype.localCompare`
202
206
  * default: false
203
207
  */
204
208
  stringLocaleCompare?: boolean;
209
+ /**
210
+ * whether to sort children when sort current column. default: false
211
+ */
212
+ sortChildren?: boolean;
205
213
  };
206
214
 
207
215
  /** th td type */
@@ -242,7 +250,6 @@ export type DragRowConfig = {
242
250
  // disabled?: (row: T, rowIndex: number) => boolean;
243
251
  };
244
252
 
245
- /** 树形配置 */
246
253
  export type TreeConfig = {
247
254
  // childrenField?: string;
248
255
  defaultExpandAll?: boolean;
@@ -253,13 +260,13 @@ export type TreeConfig = {
253
260
  /** header drag config */
254
261
  export type HeaderDragConfig<DT extends Record<string, any> = any> = {
255
262
  /**
256
- * 列交换模式
257
- * - none - 不做任何事
258
- * - insert - 插入(默认值)
259
- * - swap - 交换
263
+ * col switch mode
264
+ * - none
265
+ * - insert - (default)
266
+ * - swap
260
267
  */
261
268
  mode?: 'none' | 'insert' | 'swap';
262
- /** 禁用拖动的列 */
269
+ /** disabled drag col */
263
270
  disabled?: (col: StkTableColumn<DT>) => boolean;
264
271
  };
265
272
 
@@ -64,7 +64,8 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
64
64
  /** 键盘按下事件 */
65
65
  function handleKeydown(e: KeyboardEvent) {
66
66
  if (!virtual_on.value) return; // 非虚拟滚动使用浏览器默认滚动
67
- if (!ScrollCodesValues.includes(e.code as any)) return;
67
+ const keyCode = e.code;
68
+ if (!ScrollCodesValues.includes(keyCode as any)) return;
68
69
  if (!isMouseOver) return; // 不悬浮还是要触发键盘事件的
69
70
  e.preventDefault(); // 不触发键盘默认的箭头事件
70
71
 
@@ -76,22 +77,21 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
76
77
  const headerHeight = headless ? 0 : tableHeaders.value.length * (headerRowHeight || rowHeight);
77
78
  /** 表体的page */
78
79
  const bodyPageSize = Math.floor((containerHeight - headerHeight) / rowHeight);
79
-
80
- if (e.code === ScrollCodes.ArrowUp) {
80
+ if (keyCode=== ScrollCodes.ArrowUp) {
81
81
  scrollTo(scrollTop - rowHeight, null);
82
- } else if (e.code === ScrollCodes.ArrowRight) {
82
+ } else if (keyCode=== ScrollCodes.ArrowRight) {
83
83
  scrollTo(null, scrollLeft + 50);
84
- } else if (e.code === ScrollCodes.ArrowDown) {
84
+ } else if (keyCode=== ScrollCodes.ArrowDown) {
85
85
  scrollTo(scrollTop + rowHeight, null);
86
- } else if (e.code === ScrollCodes.ArrowLeft) {
86
+ } else if (keyCode=== ScrollCodes.ArrowLeft) {
87
87
  scrollTo(null, scrollLeft - 50);
88
- } else if (e.code === ScrollCodes.PageUp) {
88
+ } else if (keyCode=== ScrollCodes.PageUp) {
89
89
  scrollTo(scrollTop - rowHeight * bodyPageSize + headerHeight, null);
90
- } else if (e.code === ScrollCodes.PageDown) {
90
+ } else if (keyCode=== ScrollCodes.PageDown) {
91
91
  scrollTo(scrollTop + rowHeight * bodyPageSize - headerHeight, null);
92
- } else if (e.code === ScrollCodes.Home) {
92
+ } else if (keyCode=== ScrollCodes.Home) {
93
93
  scrollTo(0, null);
94
- } else if (e.code === ScrollCodes.End) {
94
+ } else if (keyCode=== ScrollCodes.End) {
95
95
  scrollTo(scrollHeight, null);
96
96
  }
97
97
  }
@@ -1,4 +1,4 @@
1
- import { CELL_KEY_SEPARATE } from '../const';
1
+ import { CELL_KEY_SEPARATE, DEFAULT_SORT_CONFIG } from '../const';
2
2
  import { Order, SortConfig, SortOption, SortState, StkTableColumn, UniqKey } from '../types';
3
3
 
4
4
  /** 是否空值 */
@@ -158,19 +158,28 @@ export function tableSort<T extends Record<string, any>>(
158
158
  ): T[] {
159
159
  if (!dataSource?.length || !sortOption) return dataSource || [];
160
160
 
161
- sortConfig = { emptyToBottom: false, ...sortConfig };
161
+ sortConfig = { ...DEFAULT_SORT_CONFIG, ...sortConfig };
162
162
  let targetDataSource = dataSource.slice();
163
163
  let sortField = sortOption.sortField || sortOption.dataIndex;
164
+ const { defaultSort, stringLocaleCompare, emptyToBottom, sortChildren } = sortConfig;
164
165
 
165
- if (!order && sortConfig.defaultSort) {
166
+ if (!order && defaultSort) {
166
167
  // 默认排序
167
- order = sortConfig.defaultSort.order;
168
- sortField = sortConfig.defaultSort.dataIndex;
168
+ order = defaultSort.order;
169
+ sortField = defaultSort.dataIndex;
169
170
  }
170
171
 
171
172
  if (typeof sortOption.sorter === 'function') {
172
173
  const customSorterData = sortOption.sorter(targetDataSource, { order, column: sortOption });
173
174
  if (customSorterData) targetDataSource = customSorterData;
175
+
176
+ // 如果开启了子节点排序且使用了自定义排序器,递归排序children
177
+ if (sortChildren) {
178
+ targetDataSource.forEach(item => {
179
+ if (!item.children?.length) return;
180
+ (item as any).children = tableSort(sortOption, order, item.children, sortConfig);
181
+ });
182
+ }
174
183
  } else if (order) {
175
184
  let { sortType } = sortOption;
176
185
  if (!sortType) sortType = typeof dataSource[0][sortField] as 'number' | 'string';
@@ -179,15 +188,19 @@ export function tableSort<T extends Record<string, any>>(
179
188
  const [valueArr, emptyArr] = separatedData(sortOption, targetDataSource, isNumber);
180
189
 
181
190
  if (order === 'asc') {
182
- valueArr.sort((a, b) => strCompare(a[sortField], b[sortField], isNumber, sortConfig.stringLocaleCompare));
191
+ valueArr.sort((a, b) => strCompare(a[sortField], b[sortField], isNumber, stringLocaleCompare));
183
192
  } else {
184
- valueArr.sort((a, b) => strCompare(b[sortField], a[sortField], isNumber, sortConfig.stringLocaleCompare));
193
+ valueArr.sort((a, b) => strCompare(b[sortField], a[sortField], isNumber, stringLocaleCompare));
185
194
  }
186
195
 
187
- if (order === 'desc' || sortConfig.emptyToBottom) {
188
- targetDataSource = valueArr.concat(emptyArr);
189
- } else {
190
- targetDataSource = emptyArr.concat(valueArr);
196
+ targetDataSource = order === 'desc' || emptyToBottom ? valueArr.concat(emptyArr) : emptyArr.concat(valueArr);
197
+
198
+ // 递归排序子节点
199
+ if (sortChildren) {
200
+ targetDataSource.forEach(item => {
201
+ if (!item.children?.length) return;
202
+ (item as any).children = tableSort(sortOption, order, item.children, sortConfig);
203
+ });
191
204
  }
192
205
  }
193
206
  return targetDataSource;