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/lib/stk-table-vue.js
CHANGED
|
@@ -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 { a as insertToOrderedArray, i as binarySearch, n as registerFeature, o as strCompare, r as useAreaSelection, s as tableSort, t as StkTable_default } from "./StkTable-
|
|
9
|
+
import { a as insertToOrderedArray, i as binarySearch, n as registerFeature, o as strCompare, r as useAreaSelection, s as tableSort, t as StkTable_default } from "./StkTable-Deyo4iqb.js";
|
|
10
10
|
import { Fragment, computed, createApp, createBlock, createElementBlock, createElementVNode, createTextVNode, defineComponent, getCurrentInstance, h, markRaw, nextTick, normalizeClass, openBlock, ref, renderSlot, resolveDynamicComponent, toDisplayString, watch, withModifiers } from "vue";
|
|
11
11
|
//#region src/StkTable/custom-cells/FilterCell/Dropdown/index.ts
|
|
12
12
|
var DropdownIns = null;
|
|
@@ -15,7 +15,7 @@ async function getDropdownIns() {
|
|
|
15
15
|
const div = document.createElement("div");
|
|
16
16
|
div.classList.add("stk-filter-dropdown-wrapper");
|
|
17
17
|
document.body.appendChild(div);
|
|
18
|
-
DropdownIns = createApp(await import("./Dropdown-
|
|
18
|
+
DropdownIns = createApp(await import("./Dropdown-iW-rY3I6.js").then((module) => module.default)).mount(div);
|
|
19
19
|
}
|
|
20
20
|
return DropdownIns;
|
|
21
21
|
}
|
|
@@ -478,4 +478,168 @@ function createCheckboxCell(options) {
|
|
|
478
478
|
};
|
|
479
479
|
}
|
|
480
480
|
//#endregion
|
|
481
|
-
|
|
481
|
+
//#region src/StkTable/custom-cells/utils/formatNumber.ts
|
|
482
|
+
/** 缩放单位阈值表(从大到小匹配) */
|
|
483
|
+
var ABBR_UNITS = {
|
|
484
|
+
cn: [[1e8, "亿"], [1e4, "万"]],
|
|
485
|
+
en: [
|
|
486
|
+
[1e9, "B"],
|
|
487
|
+
[1e6, "M"],
|
|
488
|
+
[1e3, "K"]
|
|
489
|
+
]
|
|
490
|
+
};
|
|
491
|
+
/**
|
|
492
|
+
* 给数字字符串的整数部分添加千分位分隔符。
|
|
493
|
+
* @param numStr 不含符号的正数字符串(可含小数部分)
|
|
494
|
+
*
|
|
495
|
+
* 用手动分组代替先读正则 `\B(?=(\d{3})+(?!\d))`:
|
|
496
|
+
* 后者在长数字上开销随位数非线性增长,且 split('.') 会额外分配数组。
|
|
497
|
+
*/
|
|
498
|
+
function addThousandsSeparator(numStr) {
|
|
499
|
+
const dotIndex = numStr.indexOf(".");
|
|
500
|
+
const intPart = dotIndex === -1 ? numStr : numStr.slice(0, dotIndex);
|
|
501
|
+
const len = intPart.length;
|
|
502
|
+
if (len <= 3) return numStr;
|
|
503
|
+
const firstGroupLen = len % 3 || 3;
|
|
504
|
+
let withSep = intPart.slice(0, firstGroupLen);
|
|
505
|
+
for (let i = firstGroupLen; i < len; i += 3) withSep += "," + intPart.slice(i, i + 3);
|
|
506
|
+
return dotIndex === -1 ? withSep : withSep + numStr.slice(dotIndex);
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* 数字格式化纯函数(NumberCell / ChangeCell 共享内核)。
|
|
510
|
+
*
|
|
511
|
+
* 处理管线:空值判断 → 取符号 → 百分比 → 单位缩放 → 小数位 → 千分位 → 拼装。
|
|
512
|
+
*
|
|
513
|
+
* @param value 原始值(数字或可转为数字的字符串)
|
|
514
|
+
* @param options 格式化选项
|
|
515
|
+
* @returns 格式化后的字符串;空值或非数字返回 placeholder
|
|
516
|
+
*/
|
|
517
|
+
function formatNumber(value, options = {}) {
|
|
518
|
+
const { decimals, thousands = true, prefix = "", suffix = "", showSign = false, percent = false, abbr, abbrDecimals, placeholder = "--" } = options;
|
|
519
|
+
if (value === null || value === void 0 || value === "") return placeholder;
|
|
520
|
+
const num = typeof value === "number" ? value : Number(value);
|
|
521
|
+
if (Number.isNaN(num)) return placeholder;
|
|
522
|
+
const sign = num < 0 ? "-" : showSign && num > 0 ? "+" : "";
|
|
523
|
+
let work = Math.abs(num);
|
|
524
|
+
if (percent) work = work * 100;
|
|
525
|
+
let unit = "";
|
|
526
|
+
if (abbr && !percent) {
|
|
527
|
+
const units = ABBR_UNITS[abbr];
|
|
528
|
+
for (let i = 0; i < units.length; i++) {
|
|
529
|
+
const threshold = units[i][0];
|
|
530
|
+
if (work >= threshold) {
|
|
531
|
+
work = work / threshold;
|
|
532
|
+
unit = units[i][1];
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
let fractionDigits;
|
|
538
|
+
if (unit) fractionDigits = abbrDecimals ?? decimals ?? 2;
|
|
539
|
+
else fractionDigits = decimals ?? null;
|
|
540
|
+
let numStr = fractionDigits == null ? String(work) : work.toFixed(fractionDigits);
|
|
541
|
+
if (thousands) numStr = addThousandsSeparator(numStr);
|
|
542
|
+
return `${prefix}${sign}${numStr}${unit}${percent ? "%" : ""}${suffix}`;
|
|
543
|
+
}
|
|
544
|
+
//#endregion
|
|
545
|
+
//#region src/StkTable/custom-cells/NumberCell/createNumberCell.ts
|
|
546
|
+
/**
|
|
547
|
+
* 数字格式化单元格工厂函数
|
|
548
|
+
*
|
|
549
|
+
* 纯展示型单元格:将 `cellValue` 经 {@link formatNumber} 格式化为文本。
|
|
550
|
+
* 数字对齐请在列配置上设置 `align: 'right'`。
|
|
551
|
+
*
|
|
552
|
+
* @param options 格式化选项
|
|
553
|
+
* @returns `NumberCell` 组件构造函数,使用时需调用一次:`customCell: NumberCell()`
|
|
554
|
+
*
|
|
555
|
+
* @example
|
|
556
|
+
* ```ts
|
|
557
|
+
* const { NumberCell } = createNumberCell({ decimals: 2 });
|
|
558
|
+
* const NumberCellComp = NumberCell();
|
|
559
|
+
* const columns = [
|
|
560
|
+
* { title: '现价', dataIndex: 'price', align: 'right', customCell: NumberCellComp },
|
|
561
|
+
* ];
|
|
562
|
+
* ```
|
|
563
|
+
*/
|
|
564
|
+
function createNumberCell(options) {
|
|
565
|
+
/** 单元格组件 - 用于 customCell */
|
|
566
|
+
function NumberCell() {
|
|
567
|
+
return markRaw(defineComponent({
|
|
568
|
+
props: [
|
|
569
|
+
"row",
|
|
570
|
+
"col",
|
|
571
|
+
"cellValue",
|
|
572
|
+
"rowIndex",
|
|
573
|
+
"colIndex",
|
|
574
|
+
"expanded",
|
|
575
|
+
"treeExpanded"
|
|
576
|
+
],
|
|
577
|
+
setup(props) {
|
|
578
|
+
return () => h("span", { class: "stk-number-cell" }, formatNumber(props.cellValue, options));
|
|
579
|
+
}
|
|
580
|
+
}));
|
|
581
|
+
}
|
|
582
|
+
return { NumberCell };
|
|
583
|
+
}
|
|
584
|
+
//#endregion
|
|
585
|
+
//#region src/StkTable/custom-cells/ChangeCell/createChangeCell.ts
|
|
586
|
+
/** 根据原始值判断涨跌方向 */
|
|
587
|
+
function resolveDir(rawValue) {
|
|
588
|
+
const num = rawValue === "" || rawValue == null ? NaN : Number(rawValue);
|
|
589
|
+
if (Number.isNaN(num) || num === 0) return "flat";
|
|
590
|
+
return num > 0 ? "rise" : "fall";
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* 涨跌单元格工厂函数
|
|
594
|
+
*
|
|
595
|
+
* 在 {@link formatNumber} 的基础上叠加涨跌染色与箭头。染色按 `cellValue` 正负判断,
|
|
596
|
+
* 颜色方向可通过 `colorReverse` 切换(A股 / 国际),也可用 `riseColor` 等自定义。
|
|
597
|
+
* 数字对齐请在列配置上设置 `align: 'right'`。
|
|
598
|
+
*
|
|
599
|
+
* @param options 格式化 + 染色/箭头选项
|
|
600
|
+
* @returns `ChangeCell` 组件构造函数,使用时需调用一次:`customCell: ChangeCell()`
|
|
601
|
+
*
|
|
602
|
+
* @example
|
|
603
|
+
* ```ts
|
|
604
|
+
* const { ChangeCell } = createChangeCell({ decimals: 2, showSign: true, arrow: true });
|
|
605
|
+
* const ChangeCellComp = ChangeCell();
|
|
606
|
+
* const columns = [
|
|
607
|
+
* { title: '涨跌额', dataIndex: 'change', align: 'right', customCell: ChangeCellComp },
|
|
608
|
+
* ];
|
|
609
|
+
* ```
|
|
610
|
+
*/
|
|
611
|
+
function createChangeCell(options = {}) {
|
|
612
|
+
const { colorReverse = false, arrow = false, riseColor, fallColor, flatColor } = options;
|
|
613
|
+
/** 单元格组件 - 用于 customCell */
|
|
614
|
+
function ChangeCell() {
|
|
615
|
+
return markRaw(defineComponent({
|
|
616
|
+
props: [
|
|
617
|
+
"row",
|
|
618
|
+
"col",
|
|
619
|
+
"cellValue",
|
|
620
|
+
"rowIndex",
|
|
621
|
+
"colIndex",
|
|
622
|
+
"expanded",
|
|
623
|
+
"treeExpanded"
|
|
624
|
+
],
|
|
625
|
+
setup(props) {
|
|
626
|
+
return () => {
|
|
627
|
+
const raw = props.cellValue;
|
|
628
|
+
const dir = resolveDir(raw);
|
|
629
|
+
let colorClass = "stk-change-cell--flat";
|
|
630
|
+
if (dir === "rise") colorClass = colorReverse ? "stk-change-cell--green" : "stk-change-cell--red";
|
|
631
|
+
else if (dir === "fall") colorClass = colorReverse ? "stk-change-cell--red" : "stk-change-cell--green";
|
|
632
|
+
const customColor = dir === "rise" ? riseColor : dir === "fall" ? fallColor : flatColor;
|
|
633
|
+
const arrowChar = arrow && dir !== "flat" ? dir === "rise" ? "▲" : "▼" : "";
|
|
634
|
+
return h("span", {
|
|
635
|
+
class: ["stk-change-cell", colorClass],
|
|
636
|
+
style: customColor ? { color: customColor } : void 0
|
|
637
|
+
}, [arrowChar ? h("span", { class: "stk-change-cell__arrow" }, arrowChar) : null, formatNumber(raw, options)]);
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
}));
|
|
641
|
+
}
|
|
642
|
+
return { ChangeCell };
|
|
643
|
+
}
|
|
644
|
+
//#endregion
|
|
645
|
+
export { StkTable_default as StkTable, binarySearch, createChangeCell, createCheckboxCell, createEditableCell, createFilterCell, createNumberCell, formatNumber, insertToOrderedArray, registerFeature, strCompare, tableSort, useAreaSelection };
|
package/lib/style.css
CHANGED
|
@@ -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/
|
|
@@ -139,6 +139,32 @@
|
|
|
139
139
|
cursor:pointer;
|
|
140
140
|
vertical-align:middle;
|
|
141
141
|
}
|
|
142
|
+
.stk-change-cell{
|
|
143
|
+
--stk-change-red:#e02020;
|
|
144
|
+
--stk-change-green:#00a870;
|
|
145
|
+
--stk-change-flat:#666;
|
|
146
|
+
display:inline-flex;
|
|
147
|
+
align-items:center;
|
|
148
|
+
gap:2px;
|
|
149
|
+
}
|
|
150
|
+
.stk-change-cell--red{
|
|
151
|
+
color:var(--stk-change-red);
|
|
152
|
+
}
|
|
153
|
+
.stk-change-cell--green{
|
|
154
|
+
color:var(--stk-change-green);
|
|
155
|
+
}
|
|
156
|
+
.stk-change-cell--flat{
|
|
157
|
+
color:var(--stk-change-flat);
|
|
158
|
+
}
|
|
159
|
+
.stk-change-cell__arrow{
|
|
160
|
+
font-size:0.85em;
|
|
161
|
+
line-height:1;
|
|
162
|
+
}
|
|
163
|
+
.stk-table.dark .stk-change-cell{
|
|
164
|
+
--stk-change-red:#ff5c5c;
|
|
165
|
+
--stk-change-green:#26c281;
|
|
166
|
+
--stk-change-flat:#aaa;
|
|
167
|
+
}
|
|
142
168
|
@keyframes stk-table-dim{
|
|
143
169
|
from{
|
|
144
170
|
background-color:var(--highlight-color);
|
|
@@ -226,7 +252,7 @@
|
|
|
226
252
|
--rs-bc:#4b8ef0;
|
|
227
253
|
color:#d1d1e0;
|
|
228
254
|
}
|
|
229
|
-
.stk-table.dark
|
|
255
|
+
.stk-table.dark td[data-cs-s]{
|
|
230
256
|
background-blend-mode:normal;
|
|
231
257
|
}
|
|
232
258
|
.stk-table.scrollbar-on{
|
|
@@ -255,7 +281,7 @@
|
|
|
255
281
|
pointer-events:none;
|
|
256
282
|
}
|
|
257
283
|
.stk-table.bordered{
|
|
258
|
-
border-left:
|
|
284
|
+
border-left:var(--border-width) solid var(--border-color);
|
|
259
285
|
background-image:var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
|
|
260
286
|
}
|
|
261
287
|
.stk-table.bordered th,
|
|
@@ -265,6 +291,13 @@
|
|
|
265
291
|
.stk-table.bordered thead tr:first-child th{
|
|
266
292
|
background-image:var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
|
|
267
293
|
}
|
|
294
|
+
.stk-table.bordered th.fixed-cell--border-left,
|
|
295
|
+
.stk-table.bordered td.fixed-cell--border-left{
|
|
296
|
+
background-image:var(--bg-border-left), var(--bg-border-right), var(--bg-border-bottom);
|
|
297
|
+
}
|
|
298
|
+
.stk-table.bordered thead tr:first-child th.fixed-cell--border-left{
|
|
299
|
+
background-image:var(--bg-border-left), var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
|
|
300
|
+
}
|
|
268
301
|
.stk-table.bordered-h{
|
|
269
302
|
border-left:none;
|
|
270
303
|
--bg-border-right:linear-gradient(transparent, transparent);
|
|
@@ -279,6 +312,7 @@
|
|
|
279
312
|
}
|
|
280
313
|
.stk-table.bordered-body-h tbody{
|
|
281
314
|
--bg-border-right:linear-gradient(transparent, transparent);
|
|
315
|
+
--bg-border-left:linear-gradient(transparent, transparent);
|
|
282
316
|
}
|
|
283
317
|
.stk-table.stripe:not(.vt-on) .stk-tbody-main tr:nth-child(even){
|
|
284
318
|
background-color:var(--stripe-bgc);
|
|
@@ -286,7 +320,7 @@
|
|
|
286
320
|
.stk-table.stripe.vt-on .stk-tbody-main tr:nth-child(odd){
|
|
287
321
|
background-color:var(--stripe-bgc);
|
|
288
322
|
}
|
|
289
|
-
.stk-table.stripe.area-selection .stk-tbody-main tr
|
|
323
|
+
.stk-table.stripe.area-selection .stk-tbody-main tr[data-rs-s]{
|
|
290
324
|
background-color:var(--rs-bgc);
|
|
291
325
|
}
|
|
292
326
|
.stk-table.stripe.row-hover .stk-tbody-main tr:hover{
|
|
@@ -301,7 +335,7 @@
|
|
|
301
335
|
.stk-table.row-active .stk-tbody-main tr.active{
|
|
302
336
|
background-color:var(--tr-active-bgc);
|
|
303
337
|
}
|
|
304
|
-
.stk-table .stk-tbody-main tr
|
|
338
|
+
.stk-table .stk-tbody-main tr[data-rs-s]{
|
|
305
339
|
background-color:var(--rs-bgc);
|
|
306
340
|
}
|
|
307
341
|
.stk-table .stk-tbody-main tr.row-range-start td{
|
|
@@ -495,22 +529,26 @@
|
|
|
495
529
|
.stk-table .fixed-cell{
|
|
496
530
|
background-color:inherit;
|
|
497
531
|
}
|
|
498
|
-
.stk-table
|
|
532
|
+
.stk-table td[data-cs-s]{
|
|
499
533
|
background-blend-mode:multiply;
|
|
500
534
|
background-color:var(--cs-bgc);
|
|
501
535
|
box-shadow:inset 0 0 0 0 var(--cs-bc), inset 0 0 0 0 var(--cs-bc), inset 0 0 0 0 var(--cs-bc), inset 0 0 0 0 var(--cs-bc);
|
|
502
536
|
box-shadow:inset 0 var(--cs-t, 0) 0 0 var(--cs-bc), inset 0 var(--cs-b, 0) 0 0 var(--cs-bc), inset var(--cs-l, 0) 0 0 0 var(--cs-bc), inset var(--cs-r, 0) 0 0 0 var(--cs-bc);
|
|
503
537
|
}
|
|
504
|
-
.stk-table
|
|
538
|
+
.stk-table td[data-cs-t]{
|
|
505
539
|
--cs-t:2px;
|
|
506
540
|
}
|
|
507
|
-
.stk-table .cell-
|
|
541
|
+
.stk-table td[data-cs-s].cell-hover,
|
|
542
|
+
.stk-table td[data-cs-s].cell-active{
|
|
543
|
+
background-color:var(--cs-bgc);
|
|
544
|
+
}
|
|
545
|
+
.stk-table td[data-cs-b]{
|
|
508
546
|
--cs-b:-2px;
|
|
509
547
|
}
|
|
510
|
-
.stk-table
|
|
548
|
+
.stk-table td[data-cs-l]{
|
|
511
549
|
--cs-l:2px;
|
|
512
550
|
}
|
|
513
|
-
.stk-table
|
|
551
|
+
.stk-table td[data-cs-r]{
|
|
514
552
|
--cs-r:-2px;
|
|
515
553
|
}
|
|
516
554
|
.stk-table .highlight-cell{
|
package/package.json
CHANGED
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "stk-table-vue",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "High performance realtime virtual table for vue3 and vue2.7",
|
|
5
|
-
"main": "./lib/stk-table-vue.js",
|
|
6
|
-
"types": "./lib/src/StkTable/index.d.ts",
|
|
7
|
-
"homepage": "https://ja-plus.github.io/stk-table-vue/",
|
|
8
|
-
"author": "japlus",
|
|
9
|
-
"license": "MIT",
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "https://github.com/ja-plus/stk-table-vue"
|
|
13
|
-
},
|
|
14
|
-
"bugs": {
|
|
15
|
-
"url": "https://github.com/ja-plus/stk-table-vue/issues"
|
|
16
|
-
},
|
|
17
|
-
"packageManager": "pnpm@10.7.0",
|
|
18
|
-
"directories": {
|
|
19
|
-
"test": "test"
|
|
20
|
-
},
|
|
21
|
-
"type": "module",
|
|
22
|
-
"scripts": {
|
|
23
|
-
"dev": "vite",
|
|
24
|
-
"build": "vite build",
|
|
25
|
-
"test": "vitest",
|
|
26
|
-
"docs:dev": "vitepress dev docs-src",
|
|
27
|
-
"docs:build": "vitepress build docs-src",
|
|
28
|
-
"docs:preview": "vitepress preview docs-src",
|
|
29
|
-
"docs:update": "cp -rf ./docs-src/.vitepress/dist/* ./docs"
|
|
30
|
-
},
|
|
31
|
-
"keywords": [
|
|
32
|
-
"vue",
|
|
33
|
-
"table",
|
|
34
|
-
"vue-table",
|
|
35
|
-
"virtual table",
|
|
36
|
-
"virtual-scroll",
|
|
37
|
-
"data-table",
|
|
38
|
-
"vue-component",
|
|
39
|
-
"grid",
|
|
40
|
-
"vue2",
|
|
41
|
-
"vue3",
|
|
42
|
-
"highlight",
|
|
43
|
-
"sticky",
|
|
44
|
-
"virtual",
|
|
45
|
-
"list"
|
|
46
|
-
],
|
|
47
|
-
"files": [
|
|
48
|
-
"lib",
|
|
49
|
-
"src"
|
|
50
|
-
],
|
|
51
|
-
"devDependencies": {
|
|
52
|
-
"@arco-design/web-vue": "^2.58.0",
|
|
53
|
-
"@chenglou/pretext": "^0.0.8",
|
|
54
|
-
"@types/mockjs": "^1.0.10",
|
|
55
|
-
"@types/node": "^22.18.10",
|
|
56
|
-
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
|
57
|
-
"@typescript-eslint/parser": "^7.7.0",
|
|
58
|
-
"@vitejs/plugin-vue": "^6.0.5",
|
|
59
|
-
"@vue/test-utils": "^2.4.6",
|
|
60
|
-
"ant-design-vue": "4",
|
|
61
|
-
"element-plus": "^2.14.3",
|
|
62
|
-
"eslint": "^8.57.0",
|
|
63
|
-
"eslint-config-prettier": "^9.1.0",
|
|
64
|
-
"eslint-plugin-html": "^8.1.0",
|
|
65
|
-
"eslint-plugin-prettier": "^5.1.3",
|
|
66
|
-
"eslint-plugin-vue": "^9.25.0",
|
|
67
|
-
"happy-dom": "^18.0.1",
|
|
68
|
-
"ja-contextmenu": "^1.11.0",
|
|
69
|
-
"less": "^4.2.0",
|
|
70
|
-
"mitt": "^3.0.1",
|
|
71
|
-
"mockjs": "^1.1.0",
|
|
72
|
-
"naive-ui": "2",
|
|
73
|
-
"postcss": "^8.4.47",
|
|
74
|
-
"postcss-discard-comments": "^6.0.2",
|
|
75
|
-
"postcss-preset-env": "^9.5.11",
|
|
76
|
-
"prettier": "^3.2.5",
|
|
77
|
-
"stk-table-vue": "^0.11.15",
|
|
78
|
-
"typescript": "^5.8.3",
|
|
79
|
-
"vite": "^8.1.2",
|
|
80
|
-
"vite-plugin-banner": "^0.8.1",
|
|
81
|
-
"vite-plugin-dts": "3.9.1",
|
|
82
|
-
"vitepress": "^1.6.4",
|
|
83
|
-
"vitepress-demo-plugin": "^1.5.1",
|
|
84
|
-
"vitepress-plugin-llms": "^1.13.2",
|
|
85
|
-
"vitest": "^4.1.9",
|
|
86
|
-
"vue": "^3.5.39",
|
|
87
|
-
"vue-eslint-parser": "^9.4.2"
|
|
88
|
-
}
|
|
89
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "stk-table-vue",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "High performance realtime virtual table for vue3 and vue2.7",
|
|
5
|
+
"main": "./lib/stk-table-vue.js",
|
|
6
|
+
"types": "./lib/src/StkTable/index.d.ts",
|
|
7
|
+
"homepage": "https://ja-plus.github.io/stk-table-vue/",
|
|
8
|
+
"author": "japlus",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/ja-plus/stk-table-vue"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/ja-plus/stk-table-vue/issues"
|
|
16
|
+
},
|
|
17
|
+
"packageManager": "pnpm@10.7.0",
|
|
18
|
+
"directories": {
|
|
19
|
+
"test": "test"
|
|
20
|
+
},
|
|
21
|
+
"type": "module",
|
|
22
|
+
"scripts": {
|
|
23
|
+
"dev": "vite",
|
|
24
|
+
"build": "vite build",
|
|
25
|
+
"test": "vitest",
|
|
26
|
+
"docs:dev": "vitepress dev docs-src",
|
|
27
|
+
"docs:build": "vitepress build docs-src",
|
|
28
|
+
"docs:preview": "vitepress preview docs-src",
|
|
29
|
+
"docs:update": "cp -rf ./docs-src/.vitepress/dist/* ./docs"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"vue",
|
|
33
|
+
"table",
|
|
34
|
+
"vue-table",
|
|
35
|
+
"virtual table",
|
|
36
|
+
"virtual-scroll",
|
|
37
|
+
"data-table",
|
|
38
|
+
"vue-component",
|
|
39
|
+
"grid",
|
|
40
|
+
"vue2",
|
|
41
|
+
"vue3",
|
|
42
|
+
"highlight",
|
|
43
|
+
"sticky",
|
|
44
|
+
"virtual",
|
|
45
|
+
"list"
|
|
46
|
+
],
|
|
47
|
+
"files": [
|
|
48
|
+
"lib",
|
|
49
|
+
"src"
|
|
50
|
+
],
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@arco-design/web-vue": "^2.58.0",
|
|
53
|
+
"@chenglou/pretext": "^0.0.8",
|
|
54
|
+
"@types/mockjs": "^1.0.10",
|
|
55
|
+
"@types/node": "^22.18.10",
|
|
56
|
+
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
|
57
|
+
"@typescript-eslint/parser": "^7.7.0",
|
|
58
|
+
"@vitejs/plugin-vue": "^6.0.5",
|
|
59
|
+
"@vue/test-utils": "^2.4.6",
|
|
60
|
+
"ant-design-vue": "4",
|
|
61
|
+
"element-plus": "^2.14.3",
|
|
62
|
+
"eslint": "^8.57.0",
|
|
63
|
+
"eslint-config-prettier": "^9.1.0",
|
|
64
|
+
"eslint-plugin-html": "^8.1.0",
|
|
65
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
66
|
+
"eslint-plugin-vue": "^9.25.0",
|
|
67
|
+
"happy-dom": "^18.0.1",
|
|
68
|
+
"ja-contextmenu": "^1.11.0",
|
|
69
|
+
"less": "^4.2.0",
|
|
70
|
+
"mitt": "^3.0.1",
|
|
71
|
+
"mockjs": "^1.1.0",
|
|
72
|
+
"naive-ui": "2",
|
|
73
|
+
"postcss": "^8.4.47",
|
|
74
|
+
"postcss-discard-comments": "^6.0.2",
|
|
75
|
+
"postcss-preset-env": "^9.5.11",
|
|
76
|
+
"prettier": "^3.2.5",
|
|
77
|
+
"stk-table-vue": "^0.11.15",
|
|
78
|
+
"typescript": "^5.8.3",
|
|
79
|
+
"vite": "^8.1.2",
|
|
80
|
+
"vite-plugin-banner": "^0.8.1",
|
|
81
|
+
"vite-plugin-dts": "3.9.1",
|
|
82
|
+
"vitepress": "^1.6.4",
|
|
83
|
+
"vitepress-demo-plugin": "^1.5.1",
|
|
84
|
+
"vitepress-plugin-llms": "^1.13.2",
|
|
85
|
+
"vitest": "^4.1.9",
|
|
86
|
+
"vue": "^3.5.39",
|
|
87
|
+
"vue-eslint-parser": "^9.4.2"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -911,10 +911,6 @@ const getFixedStyle = useFixedStyle<DT>(props, isRelativeMode, getFixedColPositi
|
|
|
911
911
|
|
|
912
912
|
const [highlightSteps, setHighlightDimRow, setHighlightDimCell] = useHighlight(props, stkTableId, tableContainerRef);
|
|
913
913
|
|
|
914
|
-
if (props.autoResize) {
|
|
915
|
-
useAutoResize(tableContainerRef, initVirtualScroll, props, 200);
|
|
916
|
-
}
|
|
917
|
-
|
|
918
914
|
function getRowIndex(row: DT): number {
|
|
919
915
|
const targetKey = rowKeyGen(row);
|
|
920
916
|
return dataSourceCopy.value.findIndex(item => rowKeyGen(item) === targetKey);
|
|
@@ -963,6 +959,19 @@ const [fixedCols, fixedColClassMap, updateFixedShadow] = useFixedCol(
|
|
|
963
959
|
tableContainerRef,
|
|
964
960
|
);
|
|
965
961
|
|
|
962
|
+
if (props.autoResize) {
|
|
963
|
+
useAutoResize(
|
|
964
|
+
tableContainerRef,
|
|
965
|
+
() => {
|
|
966
|
+
initVirtualScroll();
|
|
967
|
+
// 容器宽度变化后,需重新计算固定列状态
|
|
968
|
+
updateFixedShadow();
|
|
969
|
+
},
|
|
970
|
+
props,
|
|
971
|
+
200,
|
|
972
|
+
);
|
|
973
|
+
}
|
|
974
|
+
|
|
966
975
|
const [colResizeOn, isColResizing, onThResizeMouseDown] = useColResize(
|
|
967
976
|
props,
|
|
968
977
|
emits,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
.stk-change-cell {
|
|
2
|
+
// 默认(浅色)配色:涨红跌绿为 A 股习惯,颜色方向由组件按 colorReverse 决定
|
|
3
|
+
--stk-change-red: #e02020;
|
|
4
|
+
--stk-change-green: #00a870;
|
|
5
|
+
--stk-change-flat: #666;
|
|
6
|
+
|
|
7
|
+
display: inline-flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
gap: 2px;
|
|
10
|
+
|
|
11
|
+
&--red {
|
|
12
|
+
color: var(--stk-change-red);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
&--green {
|
|
16
|
+
color: var(--stk-change-green);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
&--flat {
|
|
20
|
+
color: var(--stk-change-flat);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&__arrow {
|
|
24
|
+
font-size: 0.85em;
|
|
25
|
+
line-height: 1;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 暗色主题下适当提亮,跟随表格根节点 .stk-table.dark
|
|
30
|
+
.stk-table.dark .stk-change-cell {
|
|
31
|
+
--stk-change-red: #ff5c5c;
|
|
32
|
+
--stk-change-green: #26c281;
|
|
33
|
+
--stk-change-flat: #aaa;
|
|
34
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { CustomCellProps } from '../../types';
|
|
2
|
+
import { defineComponent, h, markRaw } from 'vue';
|
|
3
|
+
import { formatNumber, type FormatNumberOptions } from '../utils/formatNumber';
|
|
4
|
+
|
|
5
|
+
/** createChangeCell 配置选项 */
|
|
6
|
+
export interface CreateChangeCellOptions extends FormatNumberOptions {
|
|
7
|
+
/** 涨跌颜色是否反转:false=A股(涨红跌绿,默认),true=国际(涨绿跌红) */
|
|
8
|
+
colorReverse?: boolean;
|
|
9
|
+
/** 是否显示涨跌箭头 ▲/▼,默认 false */
|
|
10
|
+
arrow?: boolean;
|
|
11
|
+
/** 自定义上涨颜色(覆盖默认配色,传入后不受 colorReverse 影响) */
|
|
12
|
+
riseColor?: string;
|
|
13
|
+
/** 自定义下跌颜色 */
|
|
14
|
+
fallColor?: string;
|
|
15
|
+
/** 自定义平盘颜色 */
|
|
16
|
+
flatColor?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** 涨跌方向:涨 / 跌 / 平(含空值) */
|
|
20
|
+
type ChangeDir = 'rise' | 'fall' | 'flat';
|
|
21
|
+
|
|
22
|
+
/** 根据原始值判断涨跌方向 */
|
|
23
|
+
function resolveDir(rawValue: any): ChangeDir {
|
|
24
|
+
const num = rawValue === '' || rawValue == null ? NaN : Number(rawValue);
|
|
25
|
+
if (Number.isNaN(num) || num === 0) return 'flat';
|
|
26
|
+
return num > 0 ? 'rise' : 'fall';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 涨跌单元格工厂函数
|
|
31
|
+
*
|
|
32
|
+
* 在 {@link formatNumber} 的基础上叠加涨跌染色与箭头。染色按 `cellValue` 正负判断,
|
|
33
|
+
* 颜色方向可通过 `colorReverse` 切换(A股 / 国际),也可用 `riseColor` 等自定义。
|
|
34
|
+
* 数字对齐请在列配置上设置 `align: 'right'`。
|
|
35
|
+
*
|
|
36
|
+
* @param options 格式化 + 染色/箭头选项
|
|
37
|
+
* @returns `ChangeCell` 组件构造函数,使用时需调用一次:`customCell: ChangeCell()`
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* const { ChangeCell } = createChangeCell({ decimals: 2, showSign: true, arrow: true });
|
|
42
|
+
* const ChangeCellComp = ChangeCell();
|
|
43
|
+
* const columns = [
|
|
44
|
+
* { title: '涨跌额', dataIndex: 'change', align: 'right', customCell: ChangeCellComp },
|
|
45
|
+
* ];
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function createChangeCell(options: CreateChangeCellOptions = {}) {
|
|
49
|
+
const { colorReverse = false, arrow = false, riseColor, fallColor, flatColor } = options;
|
|
50
|
+
|
|
51
|
+
/** 单元格组件 - 用于 customCell */
|
|
52
|
+
function ChangeCell() {
|
|
53
|
+
return markRaw(
|
|
54
|
+
defineComponent({
|
|
55
|
+
// eslint-disable-next-line vue/require-prop-types
|
|
56
|
+
props: ['row', 'col', 'cellValue', 'rowIndex', 'colIndex', 'expanded', 'treeExpanded'],
|
|
57
|
+
setup(props: CustomCellProps<any>) {
|
|
58
|
+
return () => {
|
|
59
|
+
const raw = props.cellValue;
|
|
60
|
+
const dir = resolveDir(raw);
|
|
61
|
+
|
|
62
|
+
// 颜色 class:涨=红/跌=绿(colorReverse 时互换),平=中性
|
|
63
|
+
let colorClass = 'stk-change-cell--flat';
|
|
64
|
+
if (dir === 'rise') colorClass = colorReverse ? 'stk-change-cell--green' : 'stk-change-cell--red';
|
|
65
|
+
else if (dir === 'fall') colorClass = colorReverse ? 'stk-change-cell--red' : 'stk-change-cell--green';
|
|
66
|
+
|
|
67
|
+
// 自定义颜色(若传)直接内联覆盖
|
|
68
|
+
const customColor = dir === 'rise' ? riseColor : dir === 'fall' ? fallColor : flatColor;
|
|
69
|
+
|
|
70
|
+
// 箭头:涨 ▲ / 跌 ▼,平及空值不显示
|
|
71
|
+
const arrowChar = arrow && dir !== 'flat' ? (dir === 'rise' ? '▲' : '▼') : ''; // TODO: 支持自定义箭头
|
|
72
|
+
|
|
73
|
+
return h(
|
|
74
|
+
'span',
|
|
75
|
+
{
|
|
76
|
+
class: ['stk-change-cell', colorClass],
|
|
77
|
+
style: customColor ? { color: customColor } : undefined,
|
|
78
|
+
},
|
|
79
|
+
[arrowChar ? h('span', { class: 'stk-change-cell__arrow' }, arrowChar) : null, formatNumber(raw, options)],
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
}),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
ChangeCell,
|
|
89
|
+
};
|
|
90
|
+
}
|