stk-table-vue 0.7.1 → 0.7.2

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.
@@ -94,7 +94,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
94
94
  /** 当前行再次点击否可以取消 (rowActive=true)*/
95
95
  rowCurrentRevokable?: boolean;
96
96
  /** 表头行高。default = rowHeight */
97
- headerRowHeight?: number | null;
97
+ headerRowHeight?: number | string | null;
98
98
  /** 虚拟滚动 */
99
99
  virtual?: boolean;
100
100
  /** x轴虚拟滚动(必须设置列宽)*/
@@ -194,8 +194,11 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
194
194
  * - true: 不使用 onwheel 滚动。鼠标滚轮滚动时更加平滑。滚动过快时会白屏。
195
195
  */
196
196
  smoothScroll?: boolean;
197
- /** 按整数行纵向滚动 */
198
- scrollRowByRow?: boolean;
197
+ /**
198
+ * 按整数行纵向滚动
199
+ * - scrollbar:仅拖动滚动条生效
200
+ */
201
+ scrollRowByRow?: boolean | "scrollbar";
199
202
  }>, {
200
203
  width: string;
201
204
  fixedMode: boolean;
@@ -372,7 +375,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
372
375
  })) | (import('./types/index').UniqKey | (PrivateRowDT & {
373
376
  children?: (PrivateRowDT & /*elided*/ any)[];
374
377
  }))[], option?: {
375
- expand? /** 是否高亮选中的行 */: boolean;
378
+ expand?: boolean;
376
379
  }) => void;
377
380
  }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
378
381
  "sort-change": (col: StkTableColumn<any> | null, order: Order, data: any[], sortConfig: SortConfig<any>) => void;
@@ -456,7 +459,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
456
459
  /** 当前行再次点击否可以取消 (rowActive=true)*/
457
460
  rowCurrentRevokable?: boolean;
458
461
  /** 表头行高。default = rowHeight */
459
- headerRowHeight?: number | null;
462
+ headerRowHeight?: number | string | null;
460
463
  /** 虚拟滚动 */
461
464
  virtual?: boolean;
462
465
  /** x轴虚拟滚动(必须设置列宽)*/
@@ -556,8 +559,11 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
556
559
  * - true: 不使用 onwheel 滚动。鼠标滚轮滚动时更加平滑。滚动过快时会白屏。
557
560
  */
558
561
  smoothScroll?: boolean;
559
- /** 按整数行纵向滚动 */
560
- scrollRowByRow?: boolean;
562
+ /**
563
+ * 按整数行纵向滚动
564
+ * - scrollbar:仅拖动滚动条生效
565
+ */
566
+ scrollRowByRow?: boolean | "scrollbar";
561
567
  }>, {
562
568
  width: string;
563
569
  fixedMode: boolean;
@@ -670,7 +676,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
670
676
  stripe: boolean;
671
677
  optimizeVue2Scroll: boolean;
672
678
  rowKey: UniqKeyProp;
673
- headerRowHeight: number | null;
679
+ headerRowHeight: number | string | null;
674
680
  fixedMode: boolean;
675
681
  theme: "light" | "dark";
676
682
  rowHover: boolean;
@@ -708,7 +714,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
708
714
  treeConfig: TreeConfig;
709
715
  cellFixedMode: "sticky" | "relative";
710
716
  smoothScroll: boolean;
711
- scrollRowByRow: boolean;
717
+ scrollRowByRow: boolean | "scrollbar";
712
718
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
713
719
  declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, ReturnType<typeof __VLS_template>>;
714
720
  export default _default;
@@ -0,0 +1,11 @@
1
+ import { Ref } from 'vue';
2
+
3
+ type Params = {
4
+ props: any;
5
+ tableContainerRef: Ref<HTMLElement | undefined>;
6
+ };
7
+ export declare function useScrollRowByRow({ props, tableContainerRef }: Params): {
8
+ isSRBRActive: import('vue').ComputedRef<any>;
9
+ isDragScroll: Ref<boolean, boolean>;
10
+ };
11
+ export {};
@@ -1,4 +1,4 @@
1
- import { createElementBlock, openBlock, createElementVNode, watch, onMounted, onBeforeUnmount, ref, computed, shallowRef, defineComponent, nextTick, toRaw, normalizeStyle, normalizeClass, unref, createCommentVNode, renderSlot, Fragment, renderList, createBlock, resolveDynamicComponent, toDisplayString, createTextVNode, withCtx, createVNode } from "vue";
1
+ import { createElementBlock, openBlock, createElementVNode, watch, onMounted, onBeforeUnmount, ref, computed, shallowRef, onUnmounted, defineComponent, nextTick, toRaw, normalizeStyle, normalizeClass, unref, createCommentVNode, renderSlot, Fragment, renderList, createBlock, resolveDynamicComponent, toDisplayString, createTextVNode, withCtx, createVNode } from "vue";
2
2
  const _export_sfc = (sfc, props) => {
3
3
  const target = sfc.__vccOpts || sfc;
4
4
  for (const [key, val] of props) {
@@ -639,7 +639,7 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
639
639
  const recursion = () => {
640
640
  window.requestAnimationFrame(
641
641
  () => {
642
- const nowTs = Date.now();
642
+ const nowTs = performance.now();
643
643
  highlightDimRowsAnimation.forEach((store, rowKeyValue) => {
644
644
  const { ts, duration } = store;
645
645
  const timeOffset = nowTs - ts;
@@ -663,13 +663,13 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
663
663
  function setHighlightDimCell(rowKeyValue, colKeyValue, option = {}) {
664
664
  var _a;
665
665
  const cellEl = (_a = tableContainerRef.value) == null ? void 0 : _a.querySelector(`[data-cell-key="${rowKeyValue}--${colKeyValue}"]`);
666
+ if (!cellEl) return;
666
667
  const { className, method, duration, keyframe } = {
667
668
  className: HIGHLIGHT_CELL_CLASS,
668
669
  method: "animation",
669
670
  ...defaultHighlightDimOption.value,
670
671
  ...option
671
672
  };
672
- if (!cellEl) return;
673
673
  if (method === "animation") {
674
674
  cellEl.animate(keyframe, duration);
675
675
  } else {
@@ -678,17 +678,16 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
678
678
  }
679
679
  function setHighlightDimRow(rowKeyValues, option = {}) {
680
680
  if (!Array.isArray(rowKeyValues)) rowKeyValues = [rowKeyValues];
681
+ if (!rowKeyValues.length) return;
681
682
  const { className, method, keyframe, duration } = {
682
683
  className: HIGHLIGHT_ROW_CLASS,
683
684
  method: "animation",
684
685
  ...defaultHighlightDimOption.value,
685
686
  ...option
686
687
  };
687
- if (method === "css") {
688
- highlightRowsInCssKeyframe(rowKeyValues, className, duration);
689
- } else if (method === "animation") {
688
+ if (method === "animation") {
690
689
  if (props.virtual) {
691
- const nowTs = Date.now();
690
+ const nowTs = performance.now();
692
691
  for (let i = 0; i < rowKeyValues.length; i++) {
693
692
  const rowKeyValue = rowKeyValues[i];
694
693
  const store = { ts: nowTs, visible: false, keyframe, duration };
@@ -703,6 +702,8 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
703
702
  rowEl.animate(keyframe, duration);
704
703
  }
705
704
  }
705
+ } else {
706
+ highlightRowsInCssKeyframe(rowKeyValues, className, duration);
706
707
  }
707
708
  }
708
709
  function highlightRowsInCssKeyframe(rowKeyValues, className, duration) {
@@ -900,6 +901,63 @@ function useRowExpand({ dataSourceCopy, rowKeyGen, emits }) {
900
901
  setRowExpand
901
902
  };
902
903
  }
904
+ function useScrollRowByRow({ props, tableContainerRef }) {
905
+ let isMouseDown = false;
906
+ let isAddListeners = false;
907
+ const isDragScroll = ref(false);
908
+ const onlyDragScroll = computed(() => props.scrollRowByRow === "scrollbar");
909
+ const isSRBRActive = computed(() => {
910
+ if (onlyDragScroll.value) {
911
+ return isDragScroll.value;
912
+ }
913
+ return props.scrollRowByRow;
914
+ });
915
+ watch(
916
+ () => onlyDragScroll.value,
917
+ (v) => {
918
+ if (v) {
919
+ addEventListener();
920
+ } else {
921
+ removeEventListener();
922
+ }
923
+ }
924
+ );
925
+ onMounted(() => {
926
+ addEventListener();
927
+ });
928
+ onUnmounted(() => {
929
+ removeEventListener();
930
+ });
931
+ function addEventListener() {
932
+ if (isAddListeners || !onlyDragScroll.value) return;
933
+ const container = tableContainerRef.value;
934
+ if (!container) return;
935
+ container.addEventListener("mousedown", handleMouseDown);
936
+ container.addEventListener("mouseup", handleMouseUp);
937
+ container.addEventListener("scroll", handleScroll);
938
+ isAddListeners = true;
939
+ }
940
+ function removeEventListener() {
941
+ const container = tableContainerRef.value;
942
+ if (!container) return;
943
+ container.removeEventListener("mousedown", handleMouseDown);
944
+ container.removeEventListener("mouseup", handleMouseUp);
945
+ container.removeEventListener("scroll", handleScroll);
946
+ isAddListeners = false;
947
+ }
948
+ function handleMouseDown() {
949
+ isMouseDown = true;
950
+ }
951
+ function handleMouseUp() {
952
+ isMouseDown = false;
953
+ isDragScroll.value = false;
954
+ }
955
+ function handleScroll() {
956
+ if (!isMouseDown) return;
957
+ isDragScroll.value = true;
958
+ }
959
+ return { isSRBRActive, isDragScroll };
960
+ }
903
961
  function useThDrag({ props, emits, colKeyGen }) {
904
962
  const findParentTH = (e) => e.target.closest("th");
905
963
  const dragConfig = computed(() => {
@@ -1064,6 +1122,125 @@ function useTrDrag({ props, emits, dataSourceCopy }) {
1064
1122
  onTrDragEnd
1065
1123
  };
1066
1124
  }
1125
+ function useTree({ props, dataSourceCopy, rowKeyGen, emits }) {
1126
+ const { defaultExpandAll, defaultExpandKeys, defaultExpandLevel } = props.treeConfig;
1127
+ function toggleTreeNode(row, col) {
1128
+ const expand = row ? !row.__T_EXPANDED__ : false;
1129
+ privateSetTreeExpand(row, { expand, col, isClick: true });
1130
+ }
1131
+ function privateSetTreeExpand(row, option) {
1132
+ const rowKeyOrRowArr = Array.isArray(row) ? row : [row];
1133
+ const tempData = dataSourceCopy.value.slice();
1134
+ for (let i = 0; i < rowKeyOrRowArr.length; i++) {
1135
+ const rowKeyOrRow = rowKeyOrRowArr[i];
1136
+ let rowKey;
1137
+ if (typeof rowKeyOrRow === "string") {
1138
+ rowKey = rowKeyOrRow;
1139
+ } else {
1140
+ rowKey = rowKeyGen(rowKeyOrRow);
1141
+ }
1142
+ const index = tempData.findIndex((it) => rowKeyGen(it) === rowKey);
1143
+ if (index === -1) {
1144
+ console.warn("treeExpandRow failed.rowKey:", rowKey);
1145
+ return;
1146
+ }
1147
+ const row2 = tempData[index];
1148
+ const level = row2.__T_LV__ || 0;
1149
+ let expanded = option == null ? void 0 : option.expand;
1150
+ if (expanded === void 0) {
1151
+ expanded = !row2.__T_EXPANDED__;
1152
+ }
1153
+ if (expanded) {
1154
+ const children = expandNode(row2, level);
1155
+ tempData.splice(index + 1, 0, ...children);
1156
+ } else {
1157
+ const deleteCount = foldNode(index, tempData, level);
1158
+ tempData.splice(index + 1, deleteCount);
1159
+ }
1160
+ setNodeExpanded(row2, expanded, level);
1161
+ if (option.isClick) {
1162
+ emits("toggle-tree-expand", { expanded: Boolean(expanded), row: row2, col: option.col });
1163
+ }
1164
+ }
1165
+ dataSourceCopy.value = tempData;
1166
+ }
1167
+ function setTreeExpand(row, option) {
1168
+ privateSetTreeExpand(row, { ...option, isClick: false });
1169
+ }
1170
+ function setNodeExpanded(row, expanded, level, parent) {
1171
+ row.__T_EXPANDED__ = expanded;
1172
+ if (level !== void 0) {
1173
+ row.__T_LV__ = level;
1174
+ }
1175
+ if (parent) {
1176
+ row.__T_PARENT_K__ = rowKeyGen(parent);
1177
+ }
1178
+ }
1179
+ function flatTreeData(data) {
1180
+ const result = [];
1181
+ (function recursion(data2, level, parent) {
1182
+ if (!data2) return;
1183
+ for (let i = 0; i < data2.length; i++) {
1184
+ const item = data2[i];
1185
+ result.push(item);
1186
+ const isExpanded = Boolean(item.__T_EXPANDED__);
1187
+ setNodeExpanded(item, isExpanded, level, parent);
1188
+ if (!isExpanded) {
1189
+ if (defaultExpandAll) {
1190
+ setNodeExpanded(item, true);
1191
+ } else {
1192
+ if (defaultExpandLevel) {
1193
+ if (level < defaultExpandLevel) {
1194
+ setNodeExpanded(item, true);
1195
+ }
1196
+ }
1197
+ if (defaultExpandKeys) {
1198
+ if (defaultExpandKeys.includes(rowKeyGen(item))) {
1199
+ setNodeExpanded(item, true);
1200
+ }
1201
+ }
1202
+ if (!item.__T_EXPANDED__) {
1203
+ continue;
1204
+ }
1205
+ }
1206
+ }
1207
+ recursion(item.children, level + 1, item);
1208
+ }
1209
+ })(data, 0);
1210
+ return result;
1211
+ }
1212
+ function expandNode(row, level) {
1213
+ let result = [];
1214
+ row.children && row.children.forEach((child) => {
1215
+ result.push(child);
1216
+ const childLv = level + 1;
1217
+ if (child.__T_EXPANDED__ && child.children) {
1218
+ const res = expandNode(child, childLv);
1219
+ result = result.concat(res);
1220
+ } else {
1221
+ setNodeExpanded(child, false, childLv, row);
1222
+ }
1223
+ });
1224
+ return result;
1225
+ }
1226
+ function foldNode(index, tempData, level) {
1227
+ let deleteCount = 0;
1228
+ for (let i = index + 1; i < tempData.length; i++) {
1229
+ const child = tempData[i];
1230
+ if (child.__T_LV__ && child.__T_LV__ > level) {
1231
+ deleteCount++;
1232
+ } else {
1233
+ break;
1234
+ }
1235
+ }
1236
+ return deleteCount;
1237
+ }
1238
+ return {
1239
+ toggleTreeNode,
1240
+ setTreeExpand,
1241
+ flatTreeData
1242
+ };
1243
+ }
1067
1244
  const VUE2_SCROLL_TIMEOUT_MS = 200;
1068
1245
  function useVirtualScroll({
1069
1246
  props,
@@ -1380,125 +1557,6 @@ function useVirtualScroll({
1380
1557
  clearAllAutoHeight
1381
1558
  };
1382
1559
  }
1383
- function useTree({ props, dataSourceCopy, rowKeyGen, emits }) {
1384
- const { defaultExpandAll, defaultExpandKeys, defaultExpandLevel } = props.treeConfig;
1385
- function toggleTreeNode(row, col) {
1386
- const expand = row ? !row.__T_EXPANDED__ : false;
1387
- privateSetTreeExpand(row, { expand, col, isClick: true });
1388
- }
1389
- function privateSetTreeExpand(row, option) {
1390
- const rowKeyOrRowArr = Array.isArray(row) ? row : [row];
1391
- const tempData = dataSourceCopy.value.slice();
1392
- for (let i = 0; i < rowKeyOrRowArr.length; i++) {
1393
- const rowKeyOrRow = rowKeyOrRowArr[i];
1394
- let rowKey;
1395
- if (typeof rowKeyOrRow === "string") {
1396
- rowKey = rowKeyOrRow;
1397
- } else {
1398
- rowKey = rowKeyGen(rowKeyOrRow);
1399
- }
1400
- const index = tempData.findIndex((it) => rowKeyGen(it) === rowKey);
1401
- if (index === -1) {
1402
- console.warn("treeExpandRow failed.rowKey:", rowKey);
1403
- return;
1404
- }
1405
- const row2 = tempData[index];
1406
- const level = row2.__T_LV__ || 0;
1407
- let expanded = option == null ? void 0 : option.expand;
1408
- if (expanded === void 0) {
1409
- expanded = !row2.__T_EXPANDED__;
1410
- }
1411
- if (expanded) {
1412
- const children = expandNode(row2, level);
1413
- tempData.splice(index + 1, 0, ...children);
1414
- } else {
1415
- const deleteCount = foldNode(index, tempData, level);
1416
- tempData.splice(index + 1, deleteCount);
1417
- }
1418
- setNodeExpanded(row2, expanded, level);
1419
- if (option.isClick) {
1420
- emits("toggle-tree-expand", { expanded: Boolean(expanded), row: row2, col: option.col });
1421
- }
1422
- }
1423
- dataSourceCopy.value = tempData;
1424
- }
1425
- function setTreeExpand(row, option) {
1426
- privateSetTreeExpand(row, { ...option, isClick: false });
1427
- }
1428
- function setNodeExpanded(row, expanded, level, parent) {
1429
- row.__T_EXPANDED__ = expanded;
1430
- if (level !== void 0) {
1431
- row.__T_LV__ = level;
1432
- }
1433
- if (parent) {
1434
- row.__T_PARENT_K__ = rowKeyGen(parent);
1435
- }
1436
- }
1437
- function flatTreeData(data) {
1438
- const result = [];
1439
- (function recursion(data2, level, parent) {
1440
- if (!data2) return;
1441
- for (let i = 0; i < data2.length; i++) {
1442
- const item = data2[i];
1443
- result.push(item);
1444
- const isExpanded = Boolean(item.__T_EXPANDED__);
1445
- setNodeExpanded(item, isExpanded, level, parent);
1446
- if (!isExpanded) {
1447
- if (defaultExpandAll) {
1448
- setNodeExpanded(item, true);
1449
- } else {
1450
- if (defaultExpandLevel) {
1451
- if (level < defaultExpandLevel) {
1452
- setNodeExpanded(item, true);
1453
- }
1454
- }
1455
- if (defaultExpandKeys) {
1456
- if (defaultExpandKeys.includes(rowKeyGen(item))) {
1457
- setNodeExpanded(item, true);
1458
- }
1459
- }
1460
- if (!item.__T_EXPANDED__) {
1461
- continue;
1462
- }
1463
- }
1464
- }
1465
- recursion(item.children, level + 1, item);
1466
- }
1467
- })(data, 0);
1468
- return result;
1469
- }
1470
- function expandNode(row, level) {
1471
- let result = [];
1472
- row.children && row.children.forEach((child) => {
1473
- result.push(child);
1474
- const childLv = level + 1;
1475
- if (child.__T_EXPANDED__ && child.children) {
1476
- const res = expandNode(child, childLv);
1477
- result = result.concat(res);
1478
- } else {
1479
- setNodeExpanded(child, false, childLv, row);
1480
- }
1481
- });
1482
- return result;
1483
- }
1484
- function foldNode(index, tempData, level) {
1485
- let deleteCount = 0;
1486
- for (let i = index + 1; i < tempData.length; i++) {
1487
- const child = tempData[i];
1488
- if (child.__T_LV__ && child.__T_LV__ > level) {
1489
- deleteCount++;
1490
- } else {
1491
- break;
1492
- }
1493
- }
1494
- return deleteCount;
1495
- }
1496
- return {
1497
- toggleTreeNode,
1498
- setTreeExpand,
1499
- flatTreeData
1500
- };
1501
- }
1502
1560
  const _hoisted_1 = ["data-col-key", "draggable", "rowspan", "colspan", "title", "onClick"];
1503
1561
  const _hoisted_2 = ["onMousedown"];
1504
1562
  const _hoisted_3 = { class: "table-header-title" };
@@ -1569,7 +1627,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1569
1627
  treeConfig: { default: () => ({}) },
1570
1628
  cellFixedMode: { default: "sticky" },
1571
1629
  smoothScroll: { type: Boolean, default: DEFAULT_SMOOTH_SCROLL },
1572
- scrollRowByRow: { type: Boolean, default: false }
1630
+ scrollRowByRow: { type: [Boolean, String], default: false }
1573
1631
  },
1574
1632
  emits: ["sort-change", "row-click", "current-change", "cell-selected", "row-dblclick", "header-row-menu", "row-menu", "cell-click", "cell-mouseenter", "cell-mouseleave", "cell-mouseover", "cell-mousedown", "header-cell-click", "scroll", "scroll-x", "col-order-change", "th-drag-start", "th-drop", "row-order-change", "col-resize", "toggle-row-expand", "toggle-tree-expand", "update:columns"],
1575
1633
  setup(__props, { expose: __expose, emit: __emit }) {
@@ -1623,6 +1681,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1623
1681
  }
1624
1682
  });
1625
1683
  const rowKeyGenCache = /* @__PURE__ */ new WeakMap();
1684
+ const { isSRBRActive } = useScrollRowByRow({ props, tableContainerRef });
1626
1685
  const { onThDragStart, onThDragOver, onThDrop, isHeaderDraggable } = useThDrag({ props, emits, colKeyGen });
1627
1686
  const { onTrDragStart, onTrDrop, onTrDragOver, onTrDragEnd, onTrDragEnter } = useTrDrag({ props, emits, dataSourceCopy });
1628
1687
  const {
@@ -1733,7 +1792,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1733
1792
  nextTick(() => initVirtualScrollY());
1734
1793
  }
1735
1794
  const sortColValue = sortCol.value;
1736
- if (sortColValue) {
1795
+ if (!isEmptyValue(sortColValue) && !props.sortRemote) {
1737
1796
  const colKey = colKeyGen.value;
1738
1797
  const column = tableHeaderLast.value.find((it) => colKey(it) === sortColValue);
1739
1798
  onColumnSort(column, false);
@@ -2273,7 +2332,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2273
2332
  "header-text-overflow": props.showHeaderOverflow,
2274
2333
  "fixed-relative-mode": isRelativeMode.value,
2275
2334
  "auto-row-height": props.autoRowHeight,
2276
- "scroll-row-by-row": props.scrollRowByRow
2335
+ "scroll-row-by-row": unref(isSRBRActive)
2277
2336
  }]),
2278
2337
  style: normalizeStyle({
2279
2338
  "--row-height": props.autoRowHeight ? void 0 : unref(virtualScroll).rowHeight + "px",
@@ -2284,7 +2343,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2284
2343
  onScroll: onTableScroll,
2285
2344
  onWheel: onTableWheel
2286
2345
  }, [
2287
- props.scrollRowByRow && _ctx.virtual ? (openBlock(), createElementBlock("div", {
2346
+ unref(isSRBRActive) && _ctx.virtual ? (openBlock(), createElementBlock("div", {
2288
2347
  key: 0,
2289
2348
  class: "row-by-row-table-height",
2290
2349
  style: normalizeStyle({ height: dataSourceCopy.value.length * unref(virtualScroll).rowHeight + "px" })
@@ -2391,7 +2450,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2391
2450
  onDragend: _cache[6] || (_cache[6] = //@ts-ignore
2392
2451
  (...args) => unref(onTrDragEnd) && unref(onTrDragEnd)(...args))
2393
2452
  }, [
2394
- unref(virtual_on) && !props.scrollRowByRow ? (openBlock(), createElementBlock("tr", {
2453
+ unref(virtual_on) && !unref(isSRBRActive) ? (openBlock(), createElementBlock("tr", {
2395
2454
  key: 0,
2396
2455
  style: normalizeStyle(`height:${unref(virtualScroll).offsetTop}px`),
2397
2456
  class: "padding-top-tr"
@@ -2526,7 +2585,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
2526
2585
  }), 128))
2527
2586
  ], 46, _hoisted_6);
2528
2587
  }), 128)),
2529
- unref(virtual_on) && !props.scrollRowByRow ? (openBlock(), createElementBlock("tr", {
2588
+ unref(virtual_on) && !unref(isSRBRActive) ? (openBlock(), createElementBlock("tr", {
2530
2589
  key: 1,
2531
2590
  style: normalizeStyle(`height: ${unref(virtual_offsetBottom)}px`)
2532
2591
  }, null, 4)) : createCommentVNode("", true)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stk-table-vue",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
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,7 +59,7 @@
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.6.17",
62
+ "stk-table-vue": "^0.7.1",
63
63
  "typescript": "^5.4.5",
64
64
  "vite": "^5.4.10",
65
65
  "vite-plugin-dts": "3.9.1",
@@ -25,7 +25,7 @@
25
25
  'header-text-overflow': props.showHeaderOverflow,
26
26
  'fixed-relative-mode': isRelativeMode,
27
27
  'auto-row-height': props.autoRowHeight,
28
- 'scroll-row-by-row': props.scrollRowByRow,
28
+ 'scroll-row-by-row': isSRBRActive,
29
29
  }"
30
30
  :style="{
31
31
  '--row-height': props.autoRowHeight ? void 0 : virtualScroll.rowHeight + 'px',
@@ -38,7 +38,7 @@
38
38
  >
39
39
  <!-- 这个元素用于整数行虚拟滚动时,撑开父容器的高度) -->
40
40
  <div
41
- v-if="props.scrollRowByRow && virtual"
41
+ v-if="isSRBRActive && virtual"
42
42
  class="row-by-row-table-height"
43
43
  :style="{ height: dataSourceCopy.length * virtualScroll.rowHeight + 'px' }"
44
44
  ></div>
@@ -114,7 +114,7 @@
114
114
  <!-- <tbody v-if="virtual_on" :style="{ height: `${virtualScroll.offsetTop}px` }"></tbody> -->
115
115
  <!-- <tbody :style="{ transform: `translateY(${virtualScroll.offsetTop}px)` }"> -->
116
116
  <tbody class="stk-tbody-main" @dragover="onTrDragOver" @dragenter="onTrDragEnter" @dragend="onTrDragEnd">
117
- <tr v-if="virtual_on && !props.scrollRowByRow" :style="`height:${virtualScroll.offsetTop}px`" class="padding-top-tr">
117
+ <tr v-if="virtual_on && !isSRBRActive" :style="`height:${virtualScroll.offsetTop}px`" class="padding-top-tr">
118
118
  <!--这个td用于配合虚拟滚动的th对应,防止列错位-->
119
119
  <td v-if="virtualX_on && fixedMode && headless" class="vt-x-left"></td>
120
120
  <template v-if="fixedMode && headless">
@@ -238,7 +238,7 @@
238
238
  </td>
239
239
  </template>
240
240
  </tr>
241
- <tr v-if="virtual_on && !props.scrollRowByRow" :style="`height: ${virtual_offsetBottom}px`"></tr>
241
+ <tr v-if="virtual_on && !isSRBRActive" :style="`height: ${virtual_offsetBottom}px`"></tr>
242
242
  </tbody>
243
243
  </table>
244
244
  <div v-if="(!dataSourceCopy || !dataSourceCopy.length) && showNoData" class="stk-table-no-data" :class="{ 'no-data-full': noDataFull }">
@@ -283,12 +283,13 @@ import { useGetFixedColPosition } from './useGetFixedColPosition';
283
283
  import { useHighlight } from './useHighlight';
284
284
  import { useKeyboardArrowScroll } from './useKeyboardArrowScroll';
285
285
  import { useRowExpand } from './useRowExpand';
286
+ import { useScrollRowByRow } from './useScrollRowByRow';
286
287
  import { useThDrag } from './useThDrag';
287
288
  import { useTrDrag } from './useTrDrag';
289
+ import { useTree } from './useTree';
288
290
  import { useVirtualScroll } from './useVirtualScroll';
289
291
  import { createStkTableId, getCalculatedColWidth, getColWidth } from './utils/constRefUtils';
290
- import { howDeepTheHeader, tableSort, transformWidthToStr } from './utils/index';
291
- import { useTree } from './useTree';
292
+ import { howDeepTheHeader, isEmptyValue, tableSort, transformWidthToStr } from './utils/index';
292
293
 
293
294
  /** Generic stands for DataType */
294
295
  type DT = any & PrivateRowDT;
@@ -331,7 +332,7 @@ const props = withDefaults(
331
332
  /** 当前行再次点击否可以取消 (rowActive=true)*/
332
333
  rowCurrentRevokable?: boolean;
333
334
  /** 表头行高。default = rowHeight */
334
- headerRowHeight?: number | null;
335
+ headerRowHeight?: number | string | null;
335
336
  /** 虚拟滚动 */
336
337
  virtual?: boolean;
337
338
  /** x轴虚拟滚动(必须设置列宽)*/
@@ -428,8 +429,11 @@ const props = withDefaults(
428
429
  * - true: 不使用 onwheel 滚动。鼠标滚轮滚动时更加平滑。滚动过快时会白屏。
429
430
  */
430
431
  smoothScroll?: boolean;
431
- /** 按整数行纵向滚动 */
432
- scrollRowByRow?: boolean;
432
+ /**
433
+ * 按整数行纵向滚动
434
+ * - scrollbar:仅拖动滚动条生效
435
+ */
436
+ scrollRowByRow?: boolean | 'scrollbar';
433
437
  }>(),
434
438
  {
435
439
  width: '',
@@ -738,6 +742,8 @@ const getEmptyCellText = computed(() => {
738
742
 
739
743
  const rowKeyGenCache = new WeakMap();
740
744
 
745
+ const { isSRBRActive } = useScrollRowByRow({ props, tableContainerRef });
746
+
741
747
  const { onThDragStart, onThDragOver, onThDrop, isHeaderDraggable } = useThDrag({ props, emits, colKeyGen });
742
748
 
743
749
  const { onTrDragStart, onTrDrop, onTrDragOver, onTrDragEnd, onTrDragEnter } = useTrDrag({ props, emits, dataSourceCopy });
@@ -870,7 +876,7 @@ watch(
870
876
  nextTick(() => initVirtualScrollY());
871
877
  }
872
878
  const sortColValue = sortCol.value;
873
- if (sortColValue) {
879
+ if (!isEmptyValue(sortColValue) && !props.sortRemote) {
874
880
  // sort
875
881
  const colKey = colKeyGen.value;
876
882
  const column = tableHeaderLast.value.find(it => colKey(it) === sortColValue);
@@ -40,18 +40,6 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
40
40
  const highlightSteps = computed(() => (highlightFrequency.value ? Math.round(highlightDuration.value / highlightFrequency.value) : null));
41
41
  /** 高亮开始 */
42
42
  const highlightFrom = computed(() => highlightColor[props.theme as 'light' | 'dark'].from);
43
- /** 高亮结束 */
44
- // const highlightTo = computed(() => highlightColor[props.theme as 'light' | 'dark'].to);
45
- // const highlightInter = computed(() => interpolateRgb(highlightFrom.value, highlightTo.value));
46
-
47
- /**
48
- * 存放高亮行的状态-使用js计算颜色
49
- * @key 行唯一键
50
- * @value 记录高亮开始时间
51
- */
52
- // const highlightDimRowsJs = new Map<UniqKey, number>();
53
- /** 是否正在计算高亮行的循环-使用js计算颜色 */
54
- // const calcHighlightDimLoopJs = false;
55
43
 
56
44
  /**
57
45
  * 存放高亮行的状态-使用animation api实现
@@ -85,7 +73,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
85
73
  const recursion = () => {
86
74
  window.requestAnimationFrame(
87
75
  () => {
88
- const nowTs = Date.now();
76
+ const nowTs = performance.now();
89
77
  highlightDimRowsAnimation.forEach((store, rowKeyValue) => {
90
78
  const { ts, duration } = store;
91
79
  const timeOffset = nowTs - ts;
@@ -110,59 +98,24 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
110
98
  recursion();
111
99
  }
112
100
 
113
- /**
114
- * js计算高亮渐暗颜色的循环
115
- */
116
- // function calcRowHighlightLoopJs() {
117
- // if (calcHighlightDimLoopJs) return;
118
- // calcHighlightDimLoopJs = true;
119
- // // js计算gradient
120
- // const recursion = () => {
121
- // window.setTimeout(() => {
122
- // const nowTs = Date.now();
123
- // highlightDimRowsJs.forEach((highlightStart, rowKeyValue) => {
124
- // /** 经过的时间 ÷ 高亮持续时间 计算出 颜色过渡进度 (0-1) */
125
- // const progress = (nowTs - highlightStart) / highlightDuration;
126
- // let bgc = '';
127
- // if (0 <= progress && progress <= 1) {
128
- // bgc = highlightInter.value(progress);
129
- // } else {
130
- // highlightDimRowsJs.delete(rowKeyValue);
131
- // }
132
- // updateRowBgcJs(rowKeyValue, bgc);
133
- // });
134
-
135
- // if (highlightDimRowsJs.size > 0) {
136
- // // 还有高亮的行,则下一次循环
137
- // recursion();
138
- // } else {
139
- // // 没有则停止循环
140
- // calcHighlightDimLoopJs = false;
141
- // highlightDimRowsJs.clear(); // TODO: 是否需要 清除
142
- // }
143
- // }, highlightFrequency || HIGHLIGHT_FREQ);
144
- // };
145
- // recursion();
146
- // }
147
-
148
101
  /**
149
102
  * 高亮一个单元格。暂不支持虚拟滚动高亮状态记忆。
150
103
  * @param rowKeyValue 一行的key
151
104
  * @param colKeyValue 列key
152
105
  * @param options.method css-使用css渲染,animation-使用animation api。默认animation;
153
106
  * @param option.className 自定义css动画的class。
154
- * @param option.keyframe Keyframe https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
107
+ * @param option.keyframe 如果自定义keyframe,则 highlightConfig.fps 将会失效。Keyframehttps://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
155
108
  * @param option.duration 动画时长。method='css'状态下,用于移除class,如果传入了className则需要与自定义的动画时间一致。
156
109
  */
157
110
  function setHighlightDimCell(rowKeyValue: UniqKey, colKeyValue: string, option: HighlightDimCellOption = {}) {
158
111
  const cellEl = tableContainerRef.value?.querySelector<HTMLElement>(`[data-cell-key="${rowKeyValue}--${colKeyValue}"]`);
112
+ if (!cellEl) return;
159
113
  const { className, method, duration, keyframe } = {
160
114
  className: HIGHLIGHT_CELL_CLASS,
161
115
  method: 'animation',
162
116
  ...defaultHighlightDimOption.value,
163
117
  ...option,
164
118
  };
165
- if (!cellEl) return;
166
119
  if (method === 'animation') {
167
120
  cellEl.animate(keyframe, duration);
168
121
  } else {
@@ -175,11 +128,12 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
175
128
  * @param rowKeyValues 行唯一键的数组
176
129
  * @param option.method css-使用css渲染,animation-使用animation api,js-使用js计算颜色。默认animation
177
130
  * @param option.className 自定义css动画的class。
178
- * @param option.keyframe Keyframehttps://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
131
+ * @param option.keyframe 如果自定义keyframe,则 highlightConfig.fps 将会失效。Keyframehttps://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
179
132
  * @param option.duration 动画时长。method='css'状态下,用于移除class,如果传入了className则需要与自定义的动画时间一致。。
180
133
  */
181
134
  function setHighlightDimRow(rowKeyValues: UniqKey[], option: HighlightDimRowOption = {}) {
182
135
  if (!Array.isArray(rowKeyValues)) rowKeyValues = [rowKeyValues];
136
+ if (!rowKeyValues.length) return;
183
137
  const { className, method, keyframe, duration } = {
184
138
  className: HIGHLIGHT_ROW_CLASS,
185
139
  method: 'animation',
@@ -187,13 +141,10 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
187
141
  ...option,
188
142
  };
189
143
 
190
- if (method === 'css') {
191
- // -------- use css keyframe
192
- highlightRowsInCssKeyframe(rowKeyValues, className, duration);
193
- } else if (method === 'animation') {
144
+ if (method === 'animation') {
194
145
  if (props.virtual) {
195
146
  // -------- 用animation 接口实现动画
196
- const nowTs = Date.now();
147
+ const nowTs = performance.now();
197
148
  for (let i = 0; i < rowKeyValues.length; i++) {
198
149
  const rowKeyValue = rowKeyValues[i];
199
150
  const store: HighlightDimRowStore = { ts: nowTs, visible: false, keyframe, duration };
@@ -209,17 +160,10 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
209
160
  rowEl.animate(keyframe, duration);
210
161
  }
211
162
  }
163
+ } else {
164
+ // -------- use css keyframe
165
+ highlightRowsInCssKeyframe(rowKeyValues, className, duration);
212
166
  }
213
- // else if (method === 'js') {
214
- // // -------- 用js计算颜色渐变的高亮方案
215
- // const nowTs = Date.now();
216
- // for (let i = 0; i < rowKeyValues.length; i++) {
217
- // const rowKeyValue = rowKeyValues[i];
218
- // highlightDimRowsJs.set(rowKeyValue, nowTs);
219
- // updateRowBgcJs(rowKeyValue, highlightFrom.value);
220
- // }
221
- // calcRowHighlightLoopJs();
222
- // }
223
167
  }
224
168
 
225
169
  /**
@@ -305,13 +249,6 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
305
249
  }
306
250
  }
307
251
 
308
- /** 更新行状态 */
309
- // function updateRowBgcJs(rowKeyValue: UniqKey, color: string) {
310
- // const rowEl = document.getElementById(stkTableId + '-' + String(rowKeyValue));
311
- // if (!rowEl) return;
312
- // rowEl.style.backgroundColor = color;
313
- // }
314
-
315
252
  return {
316
253
  highlightSteps,
317
254
  setHighlightDimRow,
@@ -0,0 +1,76 @@
1
+ import { computed, Ref, ref, onMounted, onUnmounted, watch } from 'vue';
2
+
3
+ type Params = {
4
+ props: any;
5
+ tableContainerRef: Ref<HTMLElement | undefined>;
6
+ };
7
+
8
+ export function useScrollRowByRow({ props, tableContainerRef }: Params) {
9
+ let isMouseDown = false;
10
+ let isAddListeners = false;
11
+
12
+ /**记录滚动条是否正在被拖动 */
13
+ const isDragScroll = ref(false);
14
+ const onlyDragScroll = computed(() => props.scrollRowByRow === 'scrollbar');
15
+
16
+ /** is ScrollRowByRow active */
17
+ const isSRBRActive = computed(() => {
18
+ if (onlyDragScroll.value) {
19
+ return isDragScroll.value;
20
+ }
21
+ return props.scrollRowByRow;
22
+ });
23
+
24
+ watch(
25
+ () => onlyDragScroll.value,
26
+ v => {
27
+ if (v) {
28
+ addEventListener();
29
+ } else {
30
+ removeEventListener();
31
+ }
32
+ },
33
+ );
34
+
35
+ onMounted(() => {
36
+ addEventListener();
37
+ });
38
+
39
+ onUnmounted(() => {
40
+ removeEventListener();
41
+ });
42
+
43
+ function addEventListener() {
44
+ if (isAddListeners || !onlyDragScroll.value) return;
45
+ const container = tableContainerRef.value;
46
+ if (!container) return;
47
+ container.addEventListener('mousedown', handleMouseDown);
48
+ container.addEventListener('mouseup', handleMouseUp);
49
+ container.addEventListener('scroll', handleScroll);
50
+ isAddListeners = true;
51
+ }
52
+
53
+ function removeEventListener() {
54
+ const container = tableContainerRef.value;
55
+ if (!container) return;
56
+ container.removeEventListener('mousedown', handleMouseDown);
57
+ container.removeEventListener('mouseup', handleMouseUp);
58
+ container.removeEventListener('scroll', handleScroll);
59
+ isAddListeners = false;
60
+ }
61
+
62
+ function handleMouseDown() {
63
+ isMouseDown = true;
64
+ }
65
+
66
+ function handleMouseUp() {
67
+ isMouseDown = false;
68
+ isDragScroll.value = false;
69
+ }
70
+
71
+ function handleScroll() {
72
+ if (!isMouseDown) return;
73
+ isDragScroll.value = true;
74
+ }
75
+ return { isSRBRActive, isDragScroll };
76
+ }