stk-table-vue 0.3.3 → 0.3.5
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 +17 -7
- package/lib/src/StkTable/StkTable.vue.d.ts +2 -2
- package/lib/src/StkTable/types/index.d.ts +3 -0
- package/lib/src/StkTable/useHighlight.d.ts +3 -3
- package/lib/stk-table-vue.js +34 -39
- package/package.json +9 -4
- package/src/StkTable/StkTable.vue +9 -13
- package/src/StkTable/const.ts +1 -0
- package/src/StkTable/types/index.ts +9 -1
- package/src/StkTable/useHighlight.ts +26 -25
- package/src/StkTable/useVirtualScroll.ts +17 -19
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ repo:
|
|
|
16
16
|
- [x] 虚拟滚动默认通过js计算行高亮背景色,可通过 `useCss` 设置为css @keyframe实现 。
|
|
17
17
|
- [x] 支持配置高亮参数(持续时间,颜色,频率(虚拟滚动))。(`v0.2.9`)
|
|
18
18
|
- [x] `setHighlightDimRow`/`setHighlightCellRow`支持自定义高亮css类名。(`v0.2.9`)
|
|
19
|
-
- [x] 使用 `Web Animations API` 实现高亮。
|
|
19
|
+
- [x] 使用 `Web Animations API` 实现高亮。(`v0.3.4` 变更为默认值)
|
|
20
20
|
* [x] 虚拟滚动。
|
|
21
21
|
- [x] 纵向。
|
|
22
22
|
- [x] 横向(必须设置列宽)。
|
|
@@ -223,7 +223,7 @@ export type StkProps = {
|
|
|
223
223
|
highlightConfig?: {
|
|
224
224
|
/** 高亮持续时间(s) */
|
|
225
225
|
duration?: number;
|
|
226
|
-
/**
|
|
226
|
+
/** 高亮帧率*/
|
|
227
227
|
fps?: number;
|
|
228
228
|
};
|
|
229
229
|
/** 序号列配置 */
|
|
@@ -549,13 +549,23 @@ export type SortConfig<T extends Record<string, any>> = {
|
|
|
549
549
|
### 鼠标悬浮表头时,不展示title
|
|
550
550
|
* 将 `StkTableColumn` 中的 `title` 字段置为 "" 空字符串。这样th中就没有title了。
|
|
551
551
|
* 使用 `StkTableColumn` 中的 `customHeaderCell` 属性中,自定义表头渲染。
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
552
|
+
|
|
553
|
+
## Performance optimization
|
|
554
|
+
### highlight
|
|
555
555
|
* 配置 `props.highlightConfig.fps` 指定高亮帧率。降低帧率有利于性能。
|
|
556
|
-
###
|
|
557
|
-
* 配置 `props.cellFixedMode` 为 `relative` 时,将使用相对定位实现固定列与固定表头,相较于`sticky
|
|
556
|
+
### relative fixed
|
|
557
|
+
* 配置 `props.cellFixedMode` 为 `relative` 时,将使用相对定位实现固定列与固定表头,相较于`sticky`的实现,渲染合成层更少。
|
|
558
558
|
* 问题:若开启了纵向虚拟滚动,不开启横向虚拟滚动,且不设置某些列宽时。如果纵向滚动导致某些列宽变化,则会导致右侧固定列计算错误。
|
|
559
|
+
### tr 分层
|
|
560
|
+
* 通过css选择器将 stk-table tbody tr 配置 `transform:translateZ(0)` 对每行 tr 进行分层。对性能有帮助。
|
|
561
|
+
- 提升合成层可能导致黑底红字字体颜色发生变化。
|
|
562
|
+
- 以下情况尝试开启此功能。
|
|
563
|
+
- 在 `customCell` 较多且复杂时。
|
|
564
|
+
- 大量 highlight 动画时。
|
|
559
565
|
|
|
560
566
|
## Other
|
|
561
567
|
* `$*$` 兼容注释
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
### Planed removal APi
|
|
571
|
+
* `setHighlightDimRow` 中的 `method="js"`。观察animation Api 是否足够满足使用场景。若足够满足计划在后期移除,并且可以移除 `d3-interpolate` 依赖。
|
|
@@ -186,13 +186,13 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
186
186
|
/** 设置高亮渐暗单元格 */
|
|
187
187
|
setHighlightDimCell: (rowKeyValue: string, dataIndex: string, option?: {
|
|
188
188
|
className?: string | undefined;
|
|
189
|
-
method?: "
|
|
189
|
+
method?: "animation" | "css" | undefined;
|
|
190
190
|
keyframe?: Keyframe[] | PropertyIndexedKeyframes | null | undefined;
|
|
191
191
|
duration?: number | undefined;
|
|
192
192
|
}) => void;
|
|
193
193
|
/** 设置高亮渐暗行 */
|
|
194
194
|
setHighlightDimRow: (rowKeyValues: UniqKey[], option?: {
|
|
195
|
-
method?: "
|
|
195
|
+
method?: "animation" | "css" | "js" | undefined;
|
|
196
196
|
useCss?: boolean | undefined;
|
|
197
197
|
className?: string | undefined;
|
|
198
198
|
keyframe?: Keyframe[] | PropertyIndexedKeyframes | null | undefined;
|
|
@@ -8,7 +8,10 @@ type Sorter<T> = boolean | ((data: T[], option: {
|
|
|
8
8
|
export type CustomCellFunc<T extends Record<string, any>> = (props: {
|
|
9
9
|
row: T;
|
|
10
10
|
col: StkTableColumn<T>;
|
|
11
|
+
/** row[col.dataIndex] 的值 */
|
|
11
12
|
cellValue: any;
|
|
13
|
+
rowIndex: number;
|
|
14
|
+
colIndex: number;
|
|
12
15
|
}) => VNode;
|
|
13
16
|
export type CustomHeaderCellFunc<T extends Record<string, any>> = (props: {
|
|
14
17
|
col: StkTableColumn<T>;
|
|
@@ -9,9 +9,9 @@ type Params = {
|
|
|
9
9
|
* 高亮单元格,行
|
|
10
10
|
*/
|
|
11
11
|
export declare function useHighlight({ props, stkTableId, tableContainerRef }: Params): {
|
|
12
|
-
highlightSteps: number;
|
|
12
|
+
highlightSteps: number | null;
|
|
13
13
|
setHighlightDimRow: (rowKeyValues: UniqKey[], option?: {
|
|
14
|
-
method?: '
|
|
14
|
+
method?: 'animation' | 'css' | 'js';
|
|
15
15
|
/** @deprecated 请使用method */
|
|
16
16
|
useCss?: boolean;
|
|
17
17
|
className?: string;
|
|
@@ -20,7 +20,7 @@ export declare function useHighlight({ props, stkTableId, tableContainerRef }: P
|
|
|
20
20
|
}) => void;
|
|
21
21
|
setHighlightDimCell: (rowKeyValue: string, dataIndex: string, option?: {
|
|
22
22
|
className?: string;
|
|
23
|
-
method?: '
|
|
23
|
+
method?: 'animation' | 'css';
|
|
24
24
|
keyframe?: Parameters<Animatable['animate']>['0'];
|
|
25
25
|
duration?: number;
|
|
26
26
|
}) => void;
|
package/lib/stk-table-vue.js
CHANGED
|
@@ -510,13 +510,13 @@ function useFixedStyle({
|
|
|
510
510
|
}
|
|
511
511
|
function useHighlight({ props, stkTableId, tableContainerRef }) {
|
|
512
512
|
const config = props.highlightConfig;
|
|
513
|
-
const highlightDuration = config.duration ? config.duration * 1e3 : HIGHLIGHT_DURATION;
|
|
514
|
-
const highlightFrequency = config.fps ? 1e3 / config.fps : HIGHLIGHT_FREQ;
|
|
515
513
|
const highlightColor = {
|
|
516
514
|
light: HIGHLIGHT_COLOR.light,
|
|
517
515
|
dark: HIGHLIGHT_COLOR.dark
|
|
518
516
|
};
|
|
519
|
-
const
|
|
517
|
+
const highlightDuration = config.duration ? config.duration * 1e3 : HIGHLIGHT_DURATION;
|
|
518
|
+
const highlightFrequency = config.fps && config.fps > 0 ? 1e3 / config.fps : null;
|
|
519
|
+
const highlightSteps = highlightFrequency ? Math.round(highlightDuration / highlightFrequency) : null;
|
|
520
520
|
const highlightFrom = computed(() => highlightColor[props.theme].from);
|
|
521
521
|
const highlightTo = computed(() => highlightColor[props.theme].to);
|
|
522
522
|
const highlightInter = computed(() => interpolateRgb(highlightFrom.value, highlightTo.value));
|
|
@@ -526,6 +526,13 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
|
|
|
526
526
|
let calcHighlightDimLoopAnimation = false;
|
|
527
527
|
const highlightDimRowsTimeout = /* @__PURE__ */ new Map();
|
|
528
528
|
const highlightDimCellsTimeout = /* @__PURE__ */ new Map();
|
|
529
|
+
const defaultHighlightDimOption = (() => {
|
|
530
|
+
const keyframe = { backgroundColor: [highlightFrom.value, highlightTo.value] };
|
|
531
|
+
if (highlightSteps) {
|
|
532
|
+
keyframe.easing = `steps(${highlightSteps})`;
|
|
533
|
+
}
|
|
534
|
+
return { duration: highlightDuration, keyframe };
|
|
535
|
+
})();
|
|
529
536
|
function calcRowHighlightLoop() {
|
|
530
537
|
if (calcHighlightDimLoopAnimation)
|
|
531
538
|
return;
|
|
@@ -577,20 +584,16 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
|
|
|
577
584
|
calcHighlightDimLoopJs = false;
|
|
578
585
|
highlightDimRowsJs.clear();
|
|
579
586
|
}
|
|
580
|
-
}, highlightFrequency);
|
|
587
|
+
}, highlightFrequency || HIGHLIGHT_FREQ);
|
|
581
588
|
};
|
|
582
589
|
recursion();
|
|
583
590
|
}
|
|
584
|
-
const defaultHighlightDimOption = {
|
|
585
|
-
keyframe: [{ backgroundColor: highlightFrom.value }, { backgroundColor: highlightTo.value }],
|
|
586
|
-
duration: highlightDuration
|
|
587
|
-
};
|
|
588
591
|
function setHighlightDimCell(rowKeyValue, dataIndex, option = {}) {
|
|
589
592
|
var _a;
|
|
590
593
|
const cellEl = (_a = tableContainerRef.value) == null ? void 0 : _a.querySelector(`[data-row-key="${rowKeyValue}"]>[data-index="${dataIndex}"]`);
|
|
591
594
|
const { className, method, duration, keyframe } = {
|
|
592
595
|
className: HIGHLIGHT_CELL_CLASS,
|
|
593
|
-
method: "
|
|
596
|
+
method: "animation",
|
|
594
597
|
...defaultHighlightDimOption,
|
|
595
598
|
...option
|
|
596
599
|
};
|
|
@@ -607,7 +610,7 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
|
|
|
607
610
|
rowKeyValues = [rowKeyValues];
|
|
608
611
|
const { className, method, useCss, keyframe, duration } = {
|
|
609
612
|
className: HIGHLIGHT_ROW_CLASS,
|
|
610
|
-
method:
|
|
613
|
+
method: "animation",
|
|
611
614
|
...defaultHighlightDimOption,
|
|
612
615
|
...option
|
|
613
616
|
};
|
|
@@ -906,16 +909,15 @@ function useVirtualScroll({
|
|
|
906
909
|
return width;
|
|
907
910
|
});
|
|
908
911
|
function initVirtualScrollY(height) {
|
|
912
|
+
if (height !== void 0 && typeof height !== "number") {
|
|
913
|
+
console.warn("initVirtualScrollY: height must be a number");
|
|
914
|
+
height = 0;
|
|
915
|
+
}
|
|
909
916
|
if (!virtual_on.value)
|
|
910
917
|
return;
|
|
911
918
|
const { offsetHeight, scrollTop } = tableContainerRef.value || {};
|
|
912
919
|
const { rowHeight } = virtualScroll.value;
|
|
913
|
-
|
|
914
|
-
if (typeof height === "number") {
|
|
915
|
-
containerHeight = height;
|
|
916
|
-
} else {
|
|
917
|
-
containerHeight = offsetHeight || DEFAULT_TABLE_HEIGHT;
|
|
918
|
-
}
|
|
920
|
+
const containerHeight = height || offsetHeight || DEFAULT_TABLE_HEIGHT;
|
|
919
921
|
const { headless, headerRowHeight } = props;
|
|
920
922
|
let pageSize = Math.ceil(containerHeight / rowHeight);
|
|
921
923
|
if (!headless) {
|
|
@@ -942,17 +944,12 @@ function useVirtualScroll({
|
|
|
942
944
|
if (!virtual_on.value)
|
|
943
945
|
return;
|
|
944
946
|
let startIndex = Math.floor(sTop / rowHeight);
|
|
945
|
-
if (props.stripe) {
|
|
946
|
-
startIndex -= 1;
|
|
947
|
-
}
|
|
948
947
|
if (startIndex < 0) {
|
|
949
948
|
startIndex = 0;
|
|
950
949
|
}
|
|
951
950
|
if (props.stripe && startIndex !== 0) {
|
|
952
951
|
const scrollRows = Math.abs(oldStartIndex - startIndex);
|
|
953
|
-
if (scrollRows
|
|
954
|
-
return;
|
|
955
|
-
} else if (scrollRows % 2) {
|
|
952
|
+
if (scrollRows % 2) {
|
|
956
953
|
startIndex -= 1;
|
|
957
954
|
}
|
|
958
955
|
}
|
|
@@ -984,17 +981,18 @@ function useVirtualScroll({
|
|
|
984
981
|
if (!props.virtualX)
|
|
985
982
|
return;
|
|
986
983
|
const headerLength = (_a = tableHeaderLast.value) == null ? void 0 : _a.length;
|
|
987
|
-
const { scrollLeft } = virtualScrollX.value;
|
|
988
984
|
if (!headerLength)
|
|
989
985
|
return;
|
|
986
|
+
const { scrollLeft } = virtualScrollX.value;
|
|
990
987
|
let startIndex = 0;
|
|
991
988
|
let offsetLeft = 0;
|
|
992
989
|
let colWidthSum = 0;
|
|
993
990
|
let leftColWidthSum = 0;
|
|
991
|
+
let leftFirstColRestWidth = 0;
|
|
994
992
|
for (let colIndex = 0; colIndex < headerLength; colIndex++) {
|
|
995
|
-
startIndex++;
|
|
996
993
|
const col = tableHeaderLast.value[colIndex];
|
|
997
994
|
const colWidth = getCalculatedColWidth(col);
|
|
995
|
+
startIndex++;
|
|
998
996
|
if (col.fixed === "left") {
|
|
999
997
|
leftColWidthSum += colWidth;
|
|
1000
998
|
continue;
|
|
@@ -1003,10 +1001,11 @@ function useVirtualScroll({
|
|
|
1003
1001
|
if (colWidthSum >= sLeft) {
|
|
1004
1002
|
offsetLeft = colWidthSum - colWidth;
|
|
1005
1003
|
startIndex--;
|
|
1004
|
+
leftFirstColRestWidth = colWidthSum - sLeft;
|
|
1006
1005
|
break;
|
|
1007
1006
|
}
|
|
1008
1007
|
}
|
|
1009
|
-
colWidthSum =
|
|
1008
|
+
colWidthSum = leftFirstColRestWidth;
|
|
1010
1009
|
const containerWidth = virtualScrollX.value.containerWidth - leftColWidthSum;
|
|
1011
1010
|
let endIndex = headerLength;
|
|
1012
1011
|
for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {
|
|
@@ -1570,16 +1569,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1570
1569
|
"text-overflow": props.showOverflow,
|
|
1571
1570
|
"header-text-overflow": props.showHeaderOverflow
|
|
1572
1571
|
}]),
|
|
1573
|
-
style: normalizeStyle(
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
}
|
|
1578
|
-
|
|
1579
|
-
"--highlight-duration": props.highlightConfig.duration && props.highlightConfig.duration + "s",
|
|
1580
|
-
"--highlight-timing-function": unref(highlightSteps) ? `steps(${unref(highlightSteps)})` : ""
|
|
1581
|
-
}
|
|
1582
|
-
]),
|
|
1572
|
+
style: normalizeStyle({
|
|
1573
|
+
"--row-height": unref(virtualScroll).rowHeight + "px",
|
|
1574
|
+
"--header-row-height": (props.headerRowHeight || props.rowHeight) + "px",
|
|
1575
|
+
"--highlight-duration": props.highlightConfig.duration && props.highlightConfig.duration + "s",
|
|
1576
|
+
"--highlight-timing-function": unref(highlightSteps) ? `steps(${unref(highlightSteps)})` : ""
|
|
1577
|
+
}),
|
|
1583
1578
|
onScroll: onTableScroll,
|
|
1584
1579
|
onWheel: onTableWheel
|
|
1585
1580
|
}, [
|
|
@@ -1715,10 +1710,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1715
1710
|
key: 0,
|
|
1716
1711
|
col,
|
|
1717
1712
|
row,
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
}, null, 8, ["col", "row", "
|
|
1713
|
+
rowIndex,
|
|
1714
|
+
colIndex,
|
|
1715
|
+
cellValue: row[col.dataIndex]
|
|
1716
|
+
}, null, 8, ["col", "row", "rowIndex", "colIndex", "cellValue"])) : (openBlock(), createElementBlock("div", {
|
|
1722
1717
|
key: 1,
|
|
1723
1718
|
class: "table-cell-wrapper",
|
|
1724
1719
|
title: !col.type ? row[col.dataIndex] : ""
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stk-table-vue",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "Simple realtime virtual table for vue3
|
|
3
|
+
"version": "0.3.5",
|
|
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",
|
|
7
7
|
"packageManager": "pnpm@8.14.3",
|
|
@@ -17,8 +17,13 @@
|
|
|
17
17
|
"keywords": [
|
|
18
18
|
"virtual table",
|
|
19
19
|
"vue",
|
|
20
|
+
"vue2",
|
|
21
|
+
"vue3",
|
|
20
22
|
"highlight",
|
|
21
|
-
"sticky"
|
|
23
|
+
"sticky",
|
|
24
|
+
"virtual",
|
|
25
|
+
"table",
|
|
26
|
+
"list"
|
|
22
27
|
],
|
|
23
28
|
"files": [
|
|
24
29
|
"lib",
|
|
@@ -27,7 +32,7 @@
|
|
|
27
32
|
"author": "japlus",
|
|
28
33
|
"repository": {
|
|
29
34
|
"type": "git",
|
|
30
|
-
"url": "https://
|
|
35
|
+
"url": "https://github.com/ja-plus/stk-table-vue"
|
|
31
36
|
},
|
|
32
37
|
"license": "MIT",
|
|
33
38
|
"devDependencies": {
|
|
@@ -18,16 +18,12 @@
|
|
|
18
18
|
'text-overflow': props.showOverflow,
|
|
19
19
|
'header-text-overflow': props.showHeaderOverflow,
|
|
20
20
|
}"
|
|
21
|
-
:style="
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
'--highlight-duration': props.highlightConfig.duration && props.highlightConfig.duration + 's',
|
|
28
|
-
'--highlight-timing-function': highlightSteps ? `steps(${highlightSteps})` : '',
|
|
29
|
-
},
|
|
30
|
-
]"
|
|
21
|
+
:style="{
|
|
22
|
+
'--row-height': virtualScroll.rowHeight + 'px',
|
|
23
|
+
'--header-row-height': (props.headerRowHeight || props.rowHeight) + 'px',
|
|
24
|
+
'--highlight-duration': props.highlightConfig.duration && props.highlightConfig.duration + 's',
|
|
25
|
+
'--highlight-timing-function': highlightSteps ? `steps(${highlightSteps})` : '',
|
|
26
|
+
}"
|
|
31
27
|
@scroll="onTableScroll"
|
|
32
28
|
@wheel="onTableWheel"
|
|
33
29
|
>
|
|
@@ -180,9 +176,9 @@
|
|
|
180
176
|
v-if="col.customCell"
|
|
181
177
|
:col="col"
|
|
182
178
|
:row="row"
|
|
183
|
-
:
|
|
184
|
-
:
|
|
185
|
-
:
|
|
179
|
+
:rowIndex="rowIndex"
|
|
180
|
+
:colIndex="colIndex"
|
|
181
|
+
:cellValue="row[col.dataIndex]"
|
|
186
182
|
/>
|
|
187
183
|
<div v-else class="table-cell-wrapper" :title="!col.type ? row[col.dataIndex] : ''">
|
|
188
184
|
<template v-if="col.type === 'seq'">
|
package/src/StkTable/const.ts
CHANGED
|
@@ -5,7 +5,15 @@ export type Order = null | 'asc' | 'desc';
|
|
|
5
5
|
|
|
6
6
|
type Sorter<T> = boolean | ((data: T[], option: { order: Order; column: any }) => T[]);
|
|
7
7
|
|
|
8
|
-
export type CustomCellFunc<T extends Record<string, any>> = (props: {
|
|
8
|
+
export type CustomCellFunc<T extends Record<string, any>> = (props: {
|
|
9
|
+
row: T;
|
|
10
|
+
col: StkTableColumn<T>;
|
|
11
|
+
/** row[col.dataIndex] 的值 */
|
|
12
|
+
cellValue: any;
|
|
13
|
+
rowIndex: number;
|
|
14
|
+
colIndex: number;
|
|
15
|
+
}) => VNode;
|
|
16
|
+
|
|
9
17
|
export type CustomHeaderCellFunc<T extends Record<string, any>> = (props: { col: StkTableColumn<T> }) => VNode;
|
|
10
18
|
|
|
11
19
|
/** 表格列配置 */
|
|
@@ -26,18 +26,17 @@ type HighlightDimRowStore = {
|
|
|
26
26
|
export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
|
|
27
27
|
const config: HighlightConfig = props.highlightConfig;
|
|
28
28
|
|
|
29
|
-
/** 持续时间 */
|
|
30
|
-
const highlightDuration = config.duration ? config.duration * 1000 : HIGHLIGHT_DURATION;
|
|
31
|
-
/** 高亮频率(仅虚拟滚动生效) */
|
|
32
|
-
const highlightFrequency = config.fps ? 1000 / config.fps : HIGHLIGHT_FREQ;
|
|
33
29
|
/** 高亮颜色 */
|
|
34
30
|
const highlightColor = {
|
|
35
31
|
light: HIGHLIGHT_COLOR.light,
|
|
36
32
|
dark: HIGHLIGHT_COLOR.dark,
|
|
37
33
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
/** 持续时间 */
|
|
35
|
+
const highlightDuration = config.duration ? config.duration * 1000 : HIGHLIGHT_DURATION;
|
|
36
|
+
/** 高亮频率*/
|
|
37
|
+
const highlightFrequency = config.fps && config.fps > 0 ? 1000 / config.fps : null;
|
|
38
|
+
/** 高亮帧数(非帧率),用于 timing-function: steps() */
|
|
39
|
+
const highlightSteps = highlightFrequency ? Math.round(highlightDuration / highlightFrequency) : null;
|
|
41
40
|
/** 高亮开始 */
|
|
42
41
|
const highlightFrom = computed(() => highlightColor[props.theme as 'light' | 'dark'].from);
|
|
43
42
|
/** 高亮结束 */
|
|
@@ -66,6 +65,15 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
|
|
|
66
65
|
/** 高亮后渐暗的单元格定时器 */
|
|
67
66
|
const highlightDimCellsTimeout = new Map();
|
|
68
67
|
|
|
68
|
+
/** 高亮函数的默认参数 */
|
|
69
|
+
const defaultHighlightDimOption = (() => {
|
|
70
|
+
const keyframe: PropertyIndexedKeyframes = { backgroundColor: [highlightFrom.value, highlightTo.value] };
|
|
71
|
+
if (highlightSteps) {
|
|
72
|
+
keyframe.easing = `steps(${highlightSteps})`;
|
|
73
|
+
}
|
|
74
|
+
return { duration: highlightDuration, keyframe };
|
|
75
|
+
})();
|
|
76
|
+
|
|
69
77
|
/**
|
|
70
78
|
* 计算高亮渐暗颜色的循环
|
|
71
79
|
*/
|
|
@@ -130,22 +138,16 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
|
|
|
130
138
|
calcHighlightDimLoopJs = false;
|
|
131
139
|
highlightDimRowsJs.clear(); // TODO: 是否需要 清除
|
|
132
140
|
}
|
|
133
|
-
}, highlightFrequency);
|
|
141
|
+
}, highlightFrequency || HIGHLIGHT_FREQ);
|
|
134
142
|
};
|
|
135
143
|
recursion();
|
|
136
144
|
}
|
|
137
145
|
|
|
138
|
-
/** 高亮函数的默认参数 */
|
|
139
|
-
const defaultHighlightDimOption = {
|
|
140
|
-
keyframe: [{ backgroundColor: highlightFrom.value }, { backgroundColor: highlightTo.value }],
|
|
141
|
-
duration: highlightDuration,
|
|
142
|
-
};
|
|
143
|
-
|
|
144
146
|
/**
|
|
145
|
-
*
|
|
147
|
+
* 高亮一个单元格。暂不支持虚拟滚动高亮状态记忆。
|
|
146
148
|
* @param rowKeyValue 一行的key
|
|
147
149
|
* @param dataIndex 列key
|
|
148
|
-
* @param options.method css-使用css渲染,animation-使用animation api。默认
|
|
150
|
+
* @param options.method css-使用css渲染,animation-使用animation api。默认animation;
|
|
149
151
|
* @param option.className 自定义css动画的class。
|
|
150
152
|
* @param option.keyframe 同Keyframe https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
|
|
151
153
|
* @param option.duration 动画时长。method='css'状态下,用于移除class,如果传入了className则需要与自定义的动画时间一致。
|
|
@@ -153,13 +155,12 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
|
|
|
153
155
|
function setHighlightDimCell(
|
|
154
156
|
rowKeyValue: string,
|
|
155
157
|
dataIndex: string,
|
|
156
|
-
option: { className?: string; method?: '
|
|
158
|
+
option: { className?: string; method?: 'animation' | 'css'; keyframe?: Parameters<Animatable['animate']>['0']; duration?: number } = {},
|
|
157
159
|
) {
|
|
158
|
-
// TODO: 支持动态计算高亮颜色。不易实现。需记录每一个单元格的颜色情况。
|
|
159
160
|
const cellEl = tableContainerRef.value?.querySelector<HTMLElement>(`[data-row-key="${rowKeyValue}"]>[data-index="${dataIndex}"]`);
|
|
160
161
|
const { className, method, duration, keyframe } = {
|
|
161
162
|
className: HIGHLIGHT_CELL_CLASS,
|
|
162
|
-
method: '
|
|
163
|
+
method: 'animation',
|
|
163
164
|
...defaultHighlightDimOption,
|
|
164
165
|
...option,
|
|
165
166
|
};
|
|
@@ -174,15 +175,15 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
|
|
|
174
175
|
/**
|
|
175
176
|
* 高亮一行
|
|
176
177
|
* @param rowKeyValues 行唯一键的数组
|
|
177
|
-
* @param option.method css-使用css渲染,animation-使用animation api,js-使用js
|
|
178
|
+
* @param option.method css-使用css渲染,animation-使用animation api,js-使用js计算颜色。默认animation
|
|
178
179
|
* @param option.className 自定义css动画的class。
|
|
179
|
-
* @param option.keyframe 同Keyframe
|
|
180
|
+
* @param option.keyframe 同Keyframe。 https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
|
|
180
181
|
* @param option.duration 动画时长。method='css'状态下,用于移除class,如果传入了className则需要与自定义的动画时间一致。。
|
|
181
182
|
*/
|
|
182
183
|
function setHighlightDimRow(
|
|
183
184
|
rowKeyValues: UniqKey[],
|
|
184
185
|
option: {
|
|
185
|
-
method?: '
|
|
186
|
+
method?: 'animation' | 'css' | 'js';
|
|
186
187
|
/** @deprecated 请使用method */
|
|
187
188
|
useCss?: boolean;
|
|
188
189
|
className?: string;
|
|
@@ -193,7 +194,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
|
|
|
193
194
|
if (!Array.isArray(rowKeyValues)) rowKeyValues = [rowKeyValues];
|
|
194
195
|
const { className, method, useCss, keyframe, duration } = {
|
|
195
196
|
className: HIGHLIGHT_ROW_CLASS,
|
|
196
|
-
method:
|
|
197
|
+
method: 'animation',
|
|
197
198
|
...defaultHighlightDimOption,
|
|
198
199
|
...option,
|
|
199
200
|
};
|
|
@@ -234,7 +235,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
|
|
|
234
235
|
|
|
235
236
|
/**
|
|
236
237
|
* 使用css @keyframes动画,实现高亮行动画
|
|
237
|
-
* 此方案作为兼容方式。v0.3.
|
|
238
|
+
* 此方案作为兼容方式。v0.3.4 将使用Element.animate 接口实现动画。
|
|
238
239
|
*/
|
|
239
240
|
function highlightRowsInCssKeyframe(rowKeyValues: UniqKey[], className: string, duration: number) {
|
|
240
241
|
/**是否需要重绘 */
|
|
@@ -267,7 +268,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
|
|
|
267
268
|
|
|
268
269
|
/**
|
|
269
270
|
* 使用css @keyframes动画,实现高亮单元格动画
|
|
270
|
-
* 此方案作为兼容方式。v0.3.
|
|
271
|
+
* 此方案作为兼容方式。v0.3.4 将使用Element.animate 接口实现动画。
|
|
271
272
|
*/
|
|
272
273
|
function highlightCellsInCssKeyFrame(cellEl: HTMLElement, rowKeyValue: UniqKey, className: string, duration: number) {
|
|
273
274
|
if (cellEl.classList.contains(className)) {
|
|
@@ -143,16 +143,14 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
143
143
|
* @param {number} [height] 虚拟滚动的高度
|
|
144
144
|
*/
|
|
145
145
|
function initVirtualScrollY(height?: number) {
|
|
146
|
+
if (height !== void 0 && typeof height !== 'number') {
|
|
147
|
+
console.warn('initVirtualScrollY: height must be a number');
|
|
148
|
+
height = 0;
|
|
149
|
+
}
|
|
146
150
|
if (!virtual_on.value) return;
|
|
147
151
|
const { offsetHeight, scrollTop } = tableContainerRef.value || {};
|
|
148
152
|
const { rowHeight } = virtualScroll.value;
|
|
149
|
-
|
|
150
|
-
// FIXME: 可能多次获取offsetHeight 会导致浏览器频繁重排
|
|
151
|
-
if (typeof height === 'number') {
|
|
152
|
-
containerHeight = height;
|
|
153
|
-
} else {
|
|
154
|
-
containerHeight = offsetHeight || DEFAULT_TABLE_HEIGHT;
|
|
155
|
-
}
|
|
153
|
+
const containerHeight = height || offsetHeight || DEFAULT_TABLE_HEIGHT;
|
|
156
154
|
const { headless, headerRowHeight } = props;
|
|
157
155
|
let pageSize = Math.ceil(containerHeight / rowHeight);
|
|
158
156
|
if (!headless) {
|
|
@@ -191,25 +189,19 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
191
189
|
if (!virtual_on.value) return;
|
|
192
190
|
|
|
193
191
|
let startIndex = Math.floor(sTop / rowHeight);
|
|
194
|
-
if (props.stripe) {
|
|
195
|
-
startIndex -= 1; //预渲染1行
|
|
196
|
-
}
|
|
197
192
|
if (startIndex < 0) {
|
|
198
193
|
startIndex = 0;
|
|
199
194
|
}
|
|
200
195
|
if (props.stripe && startIndex !== 0) {
|
|
201
196
|
const scrollRows = Math.abs(oldStartIndex - startIndex);
|
|
202
197
|
// 斑马纹情况下,每滚动偶数行才加载。防止斑马纹错位。
|
|
203
|
-
if (scrollRows
|
|
204
|
-
return;
|
|
205
|
-
} else if (scrollRows % 2) {
|
|
198
|
+
if (scrollRows % 2) {
|
|
206
199
|
startIndex -= 1; // 奇数-1变成偶数
|
|
207
200
|
}
|
|
208
201
|
}
|
|
209
202
|
let endIndex = startIndex + pageSize;
|
|
210
203
|
if (props.stripe) {
|
|
211
|
-
//
|
|
212
|
-
endIndex += 1;
|
|
204
|
+
endIndex += 1; // 斑马纹下多渲染一些
|
|
213
205
|
}
|
|
214
206
|
const offsetTop = startIndex * rowHeight; // startIndex之前的高度
|
|
215
207
|
endIndex = Math.min(endIndex, dataSourceCopy.value.length); // 溢出index修正
|
|
@@ -241,17 +233,22 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
241
233
|
function updateVirtualScrollX(sLeft = 0) {
|
|
242
234
|
if (!props.virtualX) return;
|
|
243
235
|
const headerLength = tableHeaderLast.value?.length;
|
|
244
|
-
const { scrollLeft } = virtualScrollX.value;
|
|
245
236
|
if (!headerLength) return;
|
|
237
|
+
|
|
238
|
+
const { scrollLeft } = virtualScrollX.value;
|
|
246
239
|
let startIndex = 0;
|
|
247
240
|
let offsetLeft = 0;
|
|
248
|
-
|
|
241
|
+
/** 列宽累加 */
|
|
249
242
|
let colWidthSum = 0;
|
|
243
|
+
/** 固定左侧列宽 */
|
|
250
244
|
let leftColWidthSum = 0;
|
|
245
|
+
/** 横向滚动时,第一列的剩余宽度 */
|
|
246
|
+
let leftFirstColRestWidth = 0;
|
|
247
|
+
|
|
251
248
|
for (let colIndex = 0; colIndex < headerLength; colIndex++) {
|
|
252
|
-
startIndex++;
|
|
253
249
|
const col = tableHeaderLast.value[colIndex];
|
|
254
250
|
const colWidth = getCalculatedColWidth(col);
|
|
251
|
+
startIndex++;
|
|
255
252
|
// fixed left 不进入计算列宽
|
|
256
253
|
if (col.fixed === 'left') {
|
|
257
254
|
leftColWidthSum += colWidth;
|
|
@@ -262,11 +259,12 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
262
259
|
if (colWidthSum >= sLeft) {
|
|
263
260
|
offsetLeft = colWidthSum - colWidth;
|
|
264
261
|
startIndex--;
|
|
262
|
+
leftFirstColRestWidth = colWidthSum - sLeft;
|
|
265
263
|
break;
|
|
266
264
|
}
|
|
267
265
|
}
|
|
268
266
|
// -----
|
|
269
|
-
colWidthSum =
|
|
267
|
+
colWidthSum = leftFirstColRestWidth;
|
|
270
268
|
const containerWidth = virtualScrollX.value.containerWidth - leftColWidthSum;
|
|
271
269
|
let endIndex = headerLength;
|
|
272
270
|
for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {
|