stk-table-vue 1.0.0 → 1.0.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.
- package/README.md +3 -0
- package/lib/{Dropdown-Clc70S1z.js → Dropdown-iW-rY3I6.js} +2 -2
- package/lib/{StkTable-QUd4TJCF.js → StkTable-Deyo4iqb.js} +151 -27
- package/lib/src/StkTable/custom-cells/ChangeCell/createChangeCell.d.ts +55 -0
- package/lib/src/StkTable/custom-cells/ChangeCell/index.d.ts +2 -0
- package/lib/src/StkTable/custom-cells/NumberCell/createNumberCell.d.ts +44 -0
- package/lib/src/StkTable/custom-cells/NumberCell/index.d.ts +2 -0
- package/lib/src/StkTable/custom-cells/utils/formatNumber.d.ts +35 -0
- package/lib/src/StkTable/index.d.ts +7 -1
- package/lib/src/StkTable/useAutoResize.d.ts +2 -2
- package/lib/stk-table-vue.js +168 -4
- package/lib/style.css +48 -10
- package/package.json +89 -89
- package/src/StkTable/StkTable.vue +13 -4
- package/src/StkTable/custom-cells/ChangeCell/ChangeCell.less +34 -0
- package/src/StkTable/custom-cells/ChangeCell/createChangeCell.ts +90 -0
- package/src/StkTable/custom-cells/ChangeCell/index.ts +4 -0
- package/src/StkTable/custom-cells/NumberCell/createNumberCell.ts +43 -0
- package/src/StkTable/custom-cells/NumberCell/index.ts +2 -0
- package/src/StkTable/custom-cells/utils/formatNumber.ts +137 -0
- package/src/StkTable/features/useAreaSelection.ts +167 -22
- package/src/StkTable/index.ts +7 -1
- package/src/StkTable/style.less +33 -10
- package/src/StkTable/useAutoResize.ts +3 -3
- package/src/StkTable/useFixedCol.ts +30 -4
- package/src/StkTable/utils/index.ts +331 -331
package/README.md
CHANGED
|
@@ -23,6 +23,9 @@ Support Vue3 and Vue2.7
|
|
|
23
23
|
|
|
24
24
|
## Documentation
|
|
25
25
|
### [Stk Table Vue Official](https://ja-plus.github.io/stk-table-vue/)
|
|
26
|
+
### [Stk Table React Official](https://ja-plus.github.io/stk-table-react/)
|
|
27
|
+
### [Stk Table Svelte Official](https://ja-plus.github.io/stk-table-svelte/)
|
|
28
|
+
### [Stk Table Solid Official](https://ja-plus.github.io/stk-table-solid/)
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
## Repo:
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* name: stk-table-vue
|
|
3
|
-
* version: v1.0.
|
|
3
|
+
* version: v1.0.2
|
|
4
4
|
* description: High performance realtime virtual table for vue3 and vue2.7
|
|
5
5
|
* author: japlus
|
|
6
6
|
* homepage: https://ja-plus.github.io/stk-table-vue/
|
|
7
7
|
* license: MIT
|
|
8
8
|
*/
|
|
9
|
-
import { t as StkTable_default } from "./StkTable-
|
|
9
|
+
import { t as StkTable_default } from "./StkTable-Deyo4iqb.js";
|
|
10
10
|
import { createElementBlock, createElementVNode, createVNode, defineComponent, h, nextTick, normalizeClass, normalizeStyle, onMounted, onUnmounted, openBlock, reactive, ref, withModifiers } from "vue";
|
|
11
11
|
//#region src/StkTable/custom-cells/FilterCell/Dropdown/index.vue?vue&type=script&setup=true&lang.ts
|
|
12
12
|
var DROPDOWN_DEFAULT_WIDTH = 300;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* name: stk-table-vue
|
|
3
|
-
* version: v1.0.
|
|
3
|
+
* version: v1.0.2
|
|
4
4
|
* description: High performance realtime virtual table for vue3 and vue2.7
|
|
5
5
|
* author: japlus
|
|
6
6
|
* homepage: https://ja-plus.github.io/stk-table-vue/
|
|
@@ -347,12 +347,12 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
347
347
|
const KEY_ESCAPE = "Escape";
|
|
348
348
|
const KEY_ESC = "Esc";
|
|
349
349
|
const KEY_C = "c";
|
|
350
|
-
const
|
|
351
|
-
const
|
|
352
|
-
const
|
|
353
|
-
const
|
|
354
|
-
const
|
|
355
|
-
const
|
|
350
|
+
const ATTR_CELL_SELECTED = "data-cs-s";
|
|
351
|
+
const ATTR_CELL_TOP = "data-cs-t";
|
|
352
|
+
const ATTR_CELL_BOTTOM = "data-cs-b";
|
|
353
|
+
const ATTR_CELL_LEFT = "data-cs-l";
|
|
354
|
+
const ATTR_CELL_RIGHT = "data-cs-r";
|
|
355
|
+
const ATTR_ROW_SELECTED = "data-rs-s";
|
|
356
356
|
const selectionRanges = ref([]);
|
|
357
357
|
const isSelecting = ref(false);
|
|
358
358
|
/** start cell */
|
|
@@ -478,10 +478,17 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
478
478
|
if (!container) return;
|
|
479
479
|
const cellHighlight = highlightCellEnabled.value;
|
|
480
480
|
const rowHighlight = highlightRowEnabled.value;
|
|
481
|
-
const oldSelectedCells = container.querySelectorAll(
|
|
482
|
-
for (let i = 0; i < oldSelectedCells.length; i++)
|
|
483
|
-
|
|
484
|
-
|
|
481
|
+
const oldSelectedCells = container.querySelectorAll(`[${ATTR_CELL_SELECTED}]`);
|
|
482
|
+
for (let i = 0; i < oldSelectedCells.length; i++) {
|
|
483
|
+
const el = oldSelectedCells[i];
|
|
484
|
+
el.removeAttribute(ATTR_CELL_SELECTED);
|
|
485
|
+
el.removeAttribute(ATTR_CELL_TOP);
|
|
486
|
+
el.removeAttribute(ATTR_CELL_BOTTOM);
|
|
487
|
+
el.removeAttribute(ATTR_CELL_LEFT);
|
|
488
|
+
el.removeAttribute(ATTR_CELL_RIGHT);
|
|
489
|
+
}
|
|
490
|
+
const oldSelectedRows = container.querySelectorAll(`[${ATTR_ROW_SELECTED}]`);
|
|
491
|
+
for (let i = 0; i < oldSelectedRows.length; i++) oldSelectedRows[i].removeAttribute(ATTR_ROW_SELECTED);
|
|
485
492
|
recomputeSelectedCellKeys();
|
|
486
493
|
const ranges = selectionRanges.value;
|
|
487
494
|
if (!ranges.length) return;
|
|
@@ -491,7 +498,7 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
491
498
|
const { minRow, maxRow } = normalizeRange(range);
|
|
492
499
|
for (let r = minRow; r <= maxRow; r++) {
|
|
493
500
|
const tr = tbody.querySelector(`tr[data-row-i="${r}"]`);
|
|
494
|
-
if (tr) tr.
|
|
501
|
+
if (tr) tr.setAttribute(ATTR_ROW_SELECTED, "");
|
|
495
502
|
}
|
|
496
503
|
}
|
|
497
504
|
if (cellHighlight) {
|
|
@@ -521,12 +528,14 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
521
528
|
if (!row || !cols[colIndex]) continue;
|
|
522
529
|
const ck = cellKeyGen(row, cols[colIndex]);
|
|
523
530
|
if (!selectedCellKeys.has(ck)) continue;
|
|
524
|
-
td.
|
|
531
|
+
td.setAttribute(ATTR_CELL_SELECTED, "");
|
|
525
532
|
if (rowIndex >= lrMinRow && rowIndex <= lrMaxRow && colIndex >= lrMinCol && colIndex <= lrMaxCol) {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
if (
|
|
529
|
-
if (
|
|
533
|
+
const effEndRow = rowIndex + (parseInt(td.getAttribute("rowspan") || "1", 10) || 1) - 1;
|
|
534
|
+
const effEndCol = colIndex + (parseInt(td.getAttribute("colspan") || "1", 10) || 1) - 1;
|
|
535
|
+
if (rowIndex === lrMinRow) td.setAttribute(ATTR_CELL_TOP, "");
|
|
536
|
+
if (effEndRow === lrMaxRow) td.setAttribute(ATTR_CELL_BOTTOM, "");
|
|
537
|
+
if (colIndex === lrMinCol) td.setAttribute(ATTR_CELL_LEFT, "");
|
|
538
|
+
if (effEndCol === lrMaxCol) td.setAttribute(ATTR_CELL_RIGHT, "");
|
|
530
539
|
}
|
|
531
540
|
}
|
|
532
541
|
}
|
|
@@ -642,6 +651,92 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
642
651
|
if (!colKey) return -1;
|
|
643
652
|
return colKeyToIndexMap.value.get(colKey) ?? -1;
|
|
644
653
|
}
|
|
654
|
+
/** 获取指定单元格的合并信息 [rowspan, colspan],无合并返回 [1, 1] */
|
|
655
|
+
function getMergeSpan(rowIndex, colIndex) {
|
|
656
|
+
const data = dataSourceCopy.value;
|
|
657
|
+
const cols = tableHeaderLast.value;
|
|
658
|
+
const row = data[rowIndex];
|
|
659
|
+
const col = cols[colIndex];
|
|
660
|
+
if (!row || !col || !col.mergeCells) return [1, 1];
|
|
661
|
+
const { rowspan = 1, colspan = 1 } = col.mergeCells({
|
|
662
|
+
row,
|
|
663
|
+
col,
|
|
664
|
+
rowIndex,
|
|
665
|
+
colIndex
|
|
666
|
+
}) || {};
|
|
667
|
+
return [rowspan || 1, colspan || 1];
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* 扩展选区范围,使其完整覆盖边界上部分选中的合并单元格
|
|
671
|
+
* en: Expand selection range to fully cover merged cells that are partially selected at boundaries
|
|
672
|
+
*/
|
|
673
|
+
function expandRangeToCoverMergedCells(range) {
|
|
674
|
+
const { minRow, maxRow, minCol, maxCol } = normalizeRange(range);
|
|
675
|
+
const data = dataSourceCopy.value;
|
|
676
|
+
const cols = tableHeaderLast.value;
|
|
677
|
+
const rowCount = data.length;
|
|
678
|
+
const colCount = cols.length;
|
|
679
|
+
const mergeColIndices = [];
|
|
680
|
+
for (let c = 0; c < colCount; c++) {
|
|
681
|
+
var _cols$c;
|
|
682
|
+
if ((_cols$c = cols[c]) === null || _cols$c === void 0 ? void 0 : _cols$c.mergeCells) mergeColIndices.push(c);
|
|
683
|
+
}
|
|
684
|
+
if (!mergeColIndices.length) return range;
|
|
685
|
+
let [eMinRow, eMaxRow, eMinCol, eMaxCol] = [
|
|
686
|
+
minRow,
|
|
687
|
+
maxRow,
|
|
688
|
+
minCol,
|
|
689
|
+
maxCol
|
|
690
|
+
];
|
|
691
|
+
let changed = true;
|
|
692
|
+
let guard = 0;
|
|
693
|
+
while (changed && guard++ < 100) {
|
|
694
|
+
changed = false;
|
|
695
|
+
for (const c of mergeColIndices) {
|
|
696
|
+
if (c < eMinCol || c > eMaxCol) continue;
|
|
697
|
+
const [rs] = getMergeSpan(eMaxRow, c);
|
|
698
|
+
if (rs > 1 && eMaxRow + rs - 1 < rowCount && eMaxRow + rs - 1 > eMaxRow) {
|
|
699
|
+
eMaxRow = eMaxRow + rs - 1;
|
|
700
|
+
changed = true;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
for (let r = eMinRow; r <= eMaxRow; r++) {
|
|
704
|
+
const [, cs] = getMergeSpan(r, eMaxCol);
|
|
705
|
+
if (cs > 1 && eMaxCol + cs - 1 < colCount && eMaxCol + cs - 1 > eMaxCol) {
|
|
706
|
+
eMaxCol = eMaxCol + cs - 1;
|
|
707
|
+
changed = true;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
for (const c of mergeColIndices) {
|
|
711
|
+
if (c < eMinCol || c > eMaxCol) continue;
|
|
712
|
+
for (let r = eMinRow - 1; r >= 0 && r > eMinRow - 500; r--) {
|
|
713
|
+
const [rs] = getMergeSpan(r, c);
|
|
714
|
+
if (rs <= 1) continue;
|
|
715
|
+
if (r + rs - 1 >= eMinRow) {
|
|
716
|
+
if (r < eMinRow) {
|
|
717
|
+
eMinRow = r;
|
|
718
|
+
changed = true;
|
|
719
|
+
}
|
|
720
|
+
} else break;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
for (let r = eMinRow; r <= eMaxRow; r++) for (let c = eMinCol - 1; c >= 0 && c > eMinCol - 500; c--) {
|
|
724
|
+
const [, cs] = getMergeSpan(r, c);
|
|
725
|
+
if (cs <= 1) continue;
|
|
726
|
+
if (c + cs - 1 >= eMinCol) {
|
|
727
|
+
if (c < eMinCol) {
|
|
728
|
+
eMinCol = c;
|
|
729
|
+
changed = true;
|
|
730
|
+
}
|
|
731
|
+
} else break;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
if (eMinRow === minRow && eMaxRow === maxRow && eMinCol === minCol && eMaxCol === maxCol) return range;
|
|
735
|
+
const { begin, end } = range.index;
|
|
736
|
+
const newBeginRow = begin.row < end.row || begin.row === end.row ? eMinRow : eMaxRow;
|
|
737
|
+
const newEndRow = begin.row < end.row || begin.row === end.row ? eMaxRow : eMinRow;
|
|
738
|
+
return makeRange(newBeginRow, begin.col <= end.col ? eMinCol : eMaxCol, newEndRow, begin.col <= end.col ? eMaxCol : eMinCol);
|
|
739
|
+
}
|
|
645
740
|
/** 获取列的左边距和宽度
|
|
646
741
|
* @param colIndex 列的绝对索引
|
|
647
742
|
* @returns [left, width]
|
|
@@ -720,10 +815,10 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
720
815
|
const colIndex = getColIndexByKey(getClosestColKey(e.target));
|
|
721
816
|
if (rowIndex < 0 || colIndex < 0) return;
|
|
722
817
|
const ctrlKey = e.ctrlKey || e.metaKey;
|
|
723
|
-
const range = makeRange(rowIndex, colIndex, rowIndex, colIndex);
|
|
818
|
+
const range = expandRangeToCoverMergedCells(makeRange(rowIndex, colIndex, rowIndex, colIndex));
|
|
724
819
|
if (e.shiftKey && anchorCell && shiftEnabled.value) {
|
|
725
820
|
const ranges = selectionRanges.value.slice();
|
|
726
|
-
const shiftRange = makeRange(anchorCell.rowIndex, anchorCell.colIndex, rowIndex, colIndex);
|
|
821
|
+
const shiftRange = expandRangeToCoverMergedCells(makeRange(anchorCell.rowIndex, anchorCell.colIndex, rowIndex, colIndex));
|
|
727
822
|
if (ranges.length) ranges[ranges.length - 1] = shiftRange;
|
|
728
823
|
else ranges.push(shiftRange);
|
|
729
824
|
selectionRanges.value = ranges;
|
|
@@ -762,7 +857,7 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
762
857
|
/** 更新最后一个选区的终点(拖拽过程中) */
|
|
763
858
|
function updateSelectionEnd(endRowIndex, endColIndex) {
|
|
764
859
|
if (!anchorCell) return;
|
|
765
|
-
const newRange = makeRange(anchorCell.rowIndex, anchorCell.colIndex, endRowIndex, endColIndex);
|
|
860
|
+
const newRange = expandRangeToCoverMergedCells(makeRange(anchorCell.rowIndex, anchorCell.colIndex, endRowIndex, endColIndex));
|
|
766
861
|
const ranges = [...selectionRanges.value];
|
|
767
862
|
if (ranges.length > 0) ranges[ranges.length - 1] = newRange;
|
|
768
863
|
else ranges.push(newRange);
|
|
@@ -825,6 +920,15 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
825
920
|
stopAutoScroll();
|
|
826
921
|
document.removeEventListener("mousemove", onDocumentMouseMove);
|
|
827
922
|
document.removeEventListener("mouseup", onDocumentMouseUp);
|
|
923
|
+
const ranges = selectionRanges.value;
|
|
924
|
+
if (ranges.length) {
|
|
925
|
+
const expanded = expandRangeToCoverMergedCells(ranges[ranges.length - 1]);
|
|
926
|
+
if (expanded !== ranges[ranges.length - 1]) {
|
|
927
|
+
const newRanges = [...ranges];
|
|
928
|
+
newRanges[newRanges.length - 1] = expanded;
|
|
929
|
+
selectionRanges.value = newRanges;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
828
932
|
emitSelectionChange();
|
|
829
933
|
}
|
|
830
934
|
function emitSelectionChange() {
|
|
@@ -1208,11 +1312,11 @@ var TagType = {
|
|
|
1208
1312
|
/**
|
|
1209
1313
|
* 窗口变化自动重置虚拟滚动
|
|
1210
1314
|
* @param tableContainerRef
|
|
1211
|
-
* @param
|
|
1315
|
+
* @param onResize 容器尺寸变化后的重算逻辑(虚拟滚动、固定列等)
|
|
1212
1316
|
* @param props
|
|
1213
1317
|
* @param debounceMs
|
|
1214
1318
|
*/
|
|
1215
|
-
function useAutoResize(tableContainerRef,
|
|
1319
|
+
function useAutoResize(tableContainerRef, onResize, props, debounceMs) {
|
|
1216
1320
|
let resizeObserver = null;
|
|
1217
1321
|
let isObserved = false;
|
|
1218
1322
|
watch(() => props.virtual, (v) => {
|
|
@@ -1257,7 +1361,7 @@ function useAutoResize(tableContainerRef, initVirtualScroll, props, debounceMs)
|
|
|
1257
1361
|
if (debounceTime) window.clearTimeout(debounceTime);
|
|
1258
1362
|
debounceTime = window.setTimeout(() => {
|
|
1259
1363
|
if (props.autoResize) {
|
|
1260
|
-
|
|
1364
|
+
onResize();
|
|
1261
1365
|
if (typeof props.autoResize === "function") props.autoResize();
|
|
1262
1366
|
}
|
|
1263
1367
|
debounceTime = 0;
|
|
@@ -1415,11 +1519,17 @@ function useFixedCol(props, colKeyGen, getFixedColPosition, tableHeaders, tableH
|
|
|
1415
1519
|
const fixedShadowCols = shallowRef([]);
|
|
1416
1520
|
/** 正在被固定的列 */
|
|
1417
1521
|
const fixedCols = shallowRef([]);
|
|
1522
|
+
/**
|
|
1523
|
+
* 需要自行绘制左边框的右固定列。
|
|
1524
|
+
* 单元格的左边框由左侧相邻单元格的 border-right 提供,右固定列吸附遮挡内容后两者不再相邻,因此需要自行绘制。
|
|
1525
|
+
*/
|
|
1526
|
+
const fixedBorderLeftCols = shallowRef([]);
|
|
1418
1527
|
/** 固定列的class */
|
|
1419
1528
|
const fixedColClassMap = computed(() => {
|
|
1420
1529
|
const colMap = /* @__PURE__ */ new Map();
|
|
1421
1530
|
const fixedShadowColsValue = fixedShadowCols.value;
|
|
1422
1531
|
const fixedColsValue = fixedCols.value;
|
|
1532
|
+
const fixedBorderLeftColsValue = fixedBorderLeftCols.value;
|
|
1423
1533
|
const colKeyFn = colKeyGen.value;
|
|
1424
1534
|
const fixedColShadow = props.fixedColShadow;
|
|
1425
1535
|
const headers = tableHeaders.value;
|
|
@@ -1436,6 +1546,7 @@ function useFixedCol(props, colKeyGen, getFixedColPosition, tableHeaders, tableH
|
|
|
1436
1546
|
classList.push("fixed-cell--" + fixed);
|
|
1437
1547
|
}
|
|
1438
1548
|
if (showShadow) classList.push("fixed-cell--shadow");
|
|
1549
|
+
if (fixed === "right" && fixedBorderLeftColsValue.includes(col)) classList.push("fixed-cell--border-left");
|
|
1439
1550
|
colMap.set(colKeyFn(col), classList);
|
|
1440
1551
|
}
|
|
1441
1552
|
}
|
|
@@ -1472,6 +1583,13 @@ function useFixedCol(props, colKeyGen, getFixedColPosition, tableHeaders, tableH
|
|
|
1472
1583
|
for (let level = 0; level < len; level++) {
|
|
1473
1584
|
const row = tableHeadersForCalc.value[level];
|
|
1474
1585
|
/**
|
|
1586
|
+
* 最右侧连续 fixed:right 列的起始下标。
|
|
1587
|
+
* 这些列的固定偏移只由其右侧固定列宽度决定,不依赖中间列的声明宽度,
|
|
1588
|
+
* 且 sticky/relative 在无横向溢出时偏移为0无副作用,因此无需判断滚动位置,始终固定。
|
|
1589
|
+
*/
|
|
1590
|
+
let rightSuffixStart = row.length;
|
|
1591
|
+
while (rightSuffixStart > 0 && row[rightSuffixStart - 1].fixed === "right") rightSuffixStart--;
|
|
1592
|
+
/**
|
|
1475
1593
|
* 左侧第n个fixed:left 计算要加上前面所有left 的列宽。
|
|
1476
1594
|
*/
|
|
1477
1595
|
let left = 0;
|
|
@@ -1485,13 +1603,16 @@ function useFixedCol(props, colKeyGen, getFixedColPosition, tableHeaders, tableH
|
|
|
1485
1603
|
leftShadowCol[level] = col;
|
|
1486
1604
|
}
|
|
1487
1605
|
left += getCalculatedColWidth(col);
|
|
1488
|
-
if (isFixedRight
|
|
1489
|
-
|
|
1490
|
-
|
|
1606
|
+
if (isFixedRight) {
|
|
1607
|
+
/** 是否需要固定。依赖列声明宽度累加,声明宽度与实际渲染宽度不一致时会失真 */
|
|
1608
|
+
const needFix = scrollLeft + clientWidth - left < position;
|
|
1609
|
+
if (i >= rightSuffixStart || needFix) fixedColsTemp.push(col);
|
|
1610
|
+
if (needFix && !rightShadowCol[level]) rightShadowCol[level] = col;
|
|
1491
1611
|
}
|
|
1492
1612
|
}
|
|
1493
1613
|
}
|
|
1494
1614
|
if (props.fixedColShadow) fixedShadowCols.value = leftShadowCol.concat(rightShadowCol).filter(Boolean);
|
|
1615
|
+
fixedBorderLeftCols.value = rightShadowCol.filter(Boolean);
|
|
1495
1616
|
fixedCols.value = fixedColsTemp;
|
|
1496
1617
|
}
|
|
1497
1618
|
return [
|
|
@@ -3793,7 +3914,6 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
|
|
|
3793
3914
|
const getFixedColPosition = useGetFixedColPosition(tableHeadersForCalc, colKeyGen);
|
|
3794
3915
|
const getFixedStyle = useFixedStyle(props, isRelativeMode, getFixedColPosition, virtualScroll, virtualScrollX, virtualX_on, virtualX_offsetRight);
|
|
3795
3916
|
const [highlightSteps, setHighlightDimRow, setHighlightDimCell] = useHighlight(props, stkTableId, tableContainerRef);
|
|
3796
|
-
if (props.autoResize) useAutoResize(tableContainerRef, initVirtualScroll, props, 200);
|
|
3797
3917
|
function getRowIndex(row) {
|
|
3798
3918
|
const targetKey = rowKeyGen(row);
|
|
3799
3919
|
return dataSourceCopy.value.findIndex((item) => rowKeyGen(item) === targetKey);
|
|
@@ -3807,6 +3927,10 @@ var StkTable_default = /* @__PURE__ */ defineComponent({
|
|
|
3807
3927
|
useKeyboardArrowScroll(tableContainerRef, props, scrollTo, virtualScroll, virtualScrollX, tableHeaders, virtual_on, areaSelectionConfig);
|
|
3808
3928
|
/** 固定列处理 */
|
|
3809
3929
|
const [fixedCols, fixedColClassMap, updateFixedShadow] = useFixedCol(props, colKeyGen, getFixedColPosition, tableHeaders, tableHeadersForCalc, tableContainerRef);
|
|
3930
|
+
if (props.autoResize) useAutoResize(tableContainerRef, () => {
|
|
3931
|
+
initVirtualScroll();
|
|
3932
|
+
updateFixedShadow();
|
|
3933
|
+
}, props, 200);
|
|
3810
3934
|
const [colResizeOn, isColResizing, onThResizeMouseDown] = useColResize(props, emits, tableContainerRef, tableHeaderLast, colResizeIndicatorRef, colKeyGen, fixedCols, clearColWidthCache);
|
|
3811
3935
|
const [toggleExpandRow, setRowExpand] = useRowExpand(emits, dataSourceCopy, rowKeyGen, onDataSourceChange);
|
|
3812
3936
|
const [toggleTreeNode, setTreeExpand, flatTreeData] = useTree(props, dataSourceCopy, rowKeyGen, emits, onDataSourceChange);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { FormatNumberOptions } from '../utils/formatNumber';
|
|
2
|
+
|
|
3
|
+
/** createChangeCell 配置选项 */
|
|
4
|
+
export interface CreateChangeCellOptions extends FormatNumberOptions {
|
|
5
|
+
/** 涨跌颜色是否反转:false=A股(涨红跌绿,默认),true=国际(涨绿跌红) */
|
|
6
|
+
colorReverse?: boolean;
|
|
7
|
+
/** 是否显示涨跌箭头 ▲/▼,默认 false */
|
|
8
|
+
arrow?: boolean;
|
|
9
|
+
/** 自定义上涨颜色(覆盖默认配色,传入后不受 colorReverse 影响) */
|
|
10
|
+
riseColor?: string;
|
|
11
|
+
/** 自定义下跌颜色 */
|
|
12
|
+
fallColor?: string;
|
|
13
|
+
/** 自定义平盘颜色 */
|
|
14
|
+
flatColor?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 涨跌单元格工厂函数
|
|
18
|
+
*
|
|
19
|
+
* 在 {@link formatNumber} 的基础上叠加涨跌染色与箭头。染色按 `cellValue` 正负判断,
|
|
20
|
+
* 颜色方向可通过 `colorReverse` 切换(A股 / 国际),也可用 `riseColor` 等自定义。
|
|
21
|
+
* 数字对齐请在列配置上设置 `align: 'right'`。
|
|
22
|
+
*
|
|
23
|
+
* @param options 格式化 + 染色/箭头选项
|
|
24
|
+
* @returns `ChangeCell` 组件构造函数,使用时需调用一次:`customCell: ChangeCell()`
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* const { ChangeCell } = createChangeCell({ decimals: 2, showSign: true, arrow: true });
|
|
29
|
+
* const ChangeCellComp = ChangeCell();
|
|
30
|
+
* const columns = [
|
|
31
|
+
* { title: '涨跌额', dataIndex: 'change', align: 'right', customCell: ChangeCellComp },
|
|
32
|
+
* ];
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function createChangeCell(options?: CreateChangeCellOptions): {
|
|
36
|
+
ChangeCell: () => import('vue').Raw<import('vue').DefineComponent<{
|
|
37
|
+
row: any;
|
|
38
|
+
col: import('../..').StkTableColumn<any>;
|
|
39
|
+
cellValue: any;
|
|
40
|
+
rowIndex: number;
|
|
41
|
+
colIndex: number;
|
|
42
|
+
expanded?: import('../..').StkTableColumn<any> | undefined;
|
|
43
|
+
treeExpanded?: boolean | undefined;
|
|
44
|
+
}, () => import('vue').VNode<import('vue').RendererNode, import('vue').RendererElement, {
|
|
45
|
+
[key: string]: any;
|
|
46
|
+
}>, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{
|
|
47
|
+
row: any;
|
|
48
|
+
col: import('../..').StkTableColumn<any>;
|
|
49
|
+
cellValue: any;
|
|
50
|
+
rowIndex: number;
|
|
51
|
+
colIndex: number;
|
|
52
|
+
expanded?: import('../..').StkTableColumn<any> | undefined;
|
|
53
|
+
treeExpanded?: boolean | undefined;
|
|
54
|
+
}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>>;
|
|
55
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { FormatNumberOptions } from '../utils/formatNumber';
|
|
2
|
+
|
|
3
|
+
/** createNumberCell 配置选项(等同于格式化选项) */
|
|
4
|
+
export interface CreateNumberCellOptions extends FormatNumberOptions {
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* 数字格式化单元格工厂函数
|
|
8
|
+
*
|
|
9
|
+
* 纯展示型单元格:将 `cellValue` 经 {@link formatNumber} 格式化为文本。
|
|
10
|
+
* 数字对齐请在列配置上设置 `align: 'right'`。
|
|
11
|
+
*
|
|
12
|
+
* @param options 格式化选项
|
|
13
|
+
* @returns `NumberCell` 组件构造函数,使用时需调用一次:`customCell: NumberCell()`
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const { NumberCell } = createNumberCell({ decimals: 2 });
|
|
18
|
+
* const NumberCellComp = NumberCell();
|
|
19
|
+
* const columns = [
|
|
20
|
+
* { title: '现价', dataIndex: 'price', align: 'right', customCell: NumberCellComp },
|
|
21
|
+
* ];
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function createNumberCell(options?: CreateNumberCellOptions): {
|
|
25
|
+
NumberCell: () => import('vue').Raw<import('vue').DefineComponent<{
|
|
26
|
+
row: any;
|
|
27
|
+
col: import('../..').StkTableColumn<any>;
|
|
28
|
+
cellValue: any;
|
|
29
|
+
rowIndex: number;
|
|
30
|
+
colIndex: number;
|
|
31
|
+
expanded?: import('../..').StkTableColumn<any> | undefined;
|
|
32
|
+
treeExpanded?: boolean | undefined;
|
|
33
|
+
}, () => import('vue').VNode<import('vue').RendererNode, import('vue').RendererElement, {
|
|
34
|
+
[key: string]: any;
|
|
35
|
+
}>, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{
|
|
36
|
+
row: any;
|
|
37
|
+
col: import('../..').StkTableColumn<any>;
|
|
38
|
+
cellValue: any;
|
|
39
|
+
rowIndex: number;
|
|
40
|
+
colIndex: number;
|
|
41
|
+
expanded?: import('../..').StkTableColumn<any> | undefined;
|
|
42
|
+
treeExpanded?: boolean | undefined;
|
|
43
|
+
}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>>;
|
|
44
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数字格式化选项
|
|
3
|
+
*
|
|
4
|
+
* NumberCell / ChangeCell 共享的格式化配置。
|
|
5
|
+
*/
|
|
6
|
+
export interface FormatNumberOptions {
|
|
7
|
+
/** 小数位数(四舍五入)。不传则不强制处理小数位 */
|
|
8
|
+
decimals?: number;
|
|
9
|
+
/** 是否使用千分位分隔符,默认 true */
|
|
10
|
+
thousands?: boolean;
|
|
11
|
+
/** 前缀,如 '¥'、'$' */
|
|
12
|
+
prefix?: string;
|
|
13
|
+
/** 后缀,如 '元'、'股' */
|
|
14
|
+
suffix?: string;
|
|
15
|
+
/** 正数是否强制显示 '+' 号,默认 false(负数始终带 '-') */
|
|
16
|
+
showSign?: boolean;
|
|
17
|
+
/** 百分比模式:值 ×100 并追加 '%',默认 false。与 abbr 互斥 */
|
|
18
|
+
percent?: boolean;
|
|
19
|
+
/** 单位缩放:'cn' = 万/亿,'en' = K/M/B。不传则不缩放。与 percent 互斥 */
|
|
20
|
+
abbr?: 'cn' | 'en';
|
|
21
|
+
/** 缩放后保留的小数位,默认 2 */
|
|
22
|
+
abbrDecimals?: number;
|
|
23
|
+
/** 空值(null/undefined/'')或非数字时的占位符,默认 '--' */
|
|
24
|
+
placeholder?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 数字格式化纯函数(NumberCell / ChangeCell 共享内核)。
|
|
28
|
+
*
|
|
29
|
+
* 处理管线:空值判断 → 取符号 → 百分比 → 单位缩放 → 小数位 → 千分位 → 拼装。
|
|
30
|
+
*
|
|
31
|
+
* @param value 原始值(数字或可转为数字的字符串)
|
|
32
|
+
* @param options 格式化选项
|
|
33
|
+
* @returns 格式化后的字符串;空值或非数字返回 placeholder
|
|
34
|
+
*/
|
|
35
|
+
export declare function formatNumber(value: unknown, options?: FormatNumberOptions): string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { useAreaSelection } from './features/index';
|
|
2
2
|
export { registerFeature } from './registerFeature';
|
|
3
3
|
export { default as StkTable } from './StkTable.vue';
|
|
4
|
-
export type { Order, SortConfig, SortOption, SortState, StkTableColumn } from './types/index';
|
|
4
|
+
export type { AreaSelectionRange, Order, SortConfig, SortOption, SortState, StkTableColumn } from './types/index';
|
|
5
5
|
export { binarySearch, insertToOrderedArray, strCompare, tableSort } from './utils';
|
|
6
6
|
export { createFilterCell } from './custom-cells/FilterCell/index';
|
|
7
7
|
export type { CreateFilterCellOption, FilterStatus } from './custom-cells/FilterCell/index';
|
|
@@ -9,3 +9,9 @@ export { createEditableCell } from './custom-cells/EditableCell/index';
|
|
|
9
9
|
export type { CreateEditableCellOptions } from './custom-cells/EditableCell/index';
|
|
10
10
|
export { createCheckboxCell } from './custom-cells/CheckboxCell/index';
|
|
11
11
|
export type { createCheckboxCellOptions } from './custom-cells/CheckboxCell/index';
|
|
12
|
+
export { createNumberCell } from './custom-cells/NumberCell/index';
|
|
13
|
+
export type { CreateNumberCellOptions } from './custom-cells/NumberCell/index';
|
|
14
|
+
export { createChangeCell } from './custom-cells/ChangeCell/index';
|
|
15
|
+
export type { CreateChangeCellOptions } from './custom-cells/ChangeCell/index';
|
|
16
|
+
export { formatNumber } from './custom-cells/utils/formatNumber';
|
|
17
|
+
export type { FormatNumberOptions } from './custom-cells/utils/formatNumber';
|
|
@@ -3,8 +3,8 @@ import { Ref } from 'vue';
|
|
|
3
3
|
/**
|
|
4
4
|
* 窗口变化自动重置虚拟滚动
|
|
5
5
|
* @param tableContainerRef
|
|
6
|
-
* @param
|
|
6
|
+
* @param onResize 容器尺寸变化后的重算逻辑(虚拟滚动、固定列等)
|
|
7
7
|
* @param props
|
|
8
8
|
* @param debounceMs
|
|
9
9
|
*/
|
|
10
|
-
export declare function useAutoResize(tableContainerRef: Ref<HTMLElement | undefined>,
|
|
10
|
+
export declare function useAutoResize(tableContainerRef: Ref<HTMLElement | undefined>, onResize: () => void, props: any, debounceMs: number): void;
|