stk-table-vue 0.3.3 → 0.3.4
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 +14 -7
- package/lib/src/StkTable/StkTable.vue.d.ts +2 -2
- package/lib/src/StkTable/useHighlight.d.ts +3 -3
- package/lib/stk-table-vue.js +26 -35
- package/package.json +8 -3
- package/src/StkTable/StkTable.vue +6 -10
- package/src/StkTable/const.ts +1 -0
- package/src/StkTable/useHighlight.ts +26 -25
- package/src/StkTable/useVirtualScroll.ts +13 -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,20 @@ export type SortConfig<T extends Record<string, any>> = {
|
|
|
549
549
|
### 鼠标悬浮表头时,不展示title
|
|
550
550
|
* 将 `StkTableColumn` 中的 `title` 字段置为 "" 空字符串。这样th中就没有title了。
|
|
551
551
|
* 使用 `StkTableColumn` 中的 `customHeaderCell` 属性中,自定义表头渲染。
|
|
552
|
-
### 高亮性能
|
|
553
|
-
* 在虚拟滚动下高亮强制使用css @keyframes 实现动画。`setHighlightDimRow`/`setHighlightCellRow` 最后一个参数传入 `{method: 'css'}` 即可。(滚动后动画会中断)
|
|
554
|
-
* 指定 `{method:'animation'}` 在虚拟滚动下使用animation api实现动画。好处是动画流畅,且滚动后动画不中断。
|
|
555
|
-
* 配置 `props.highlightConfig.fps` 指定高亮帧率。降低帧率有利于性能。
|
|
556
552
|
### 性能
|
|
557
|
-
|
|
553
|
+
#### highlight
|
|
554
|
+
* 在虚拟滚动下高亮强制使用 `css @keyframes` 实现动画。`setHighlightDimRow`/`setHighlightCellRow` 最后一个参数传入 `{method: 'css'}` 即可。(滚动后动画会中断)
|
|
555
|
+
* 指定 `{method:'animation'}` 在虚拟滚动下使用animation api实现动画。好处是动画流畅,且滚动后动画不中断。坏处是不支持帧率配置。
|
|
556
|
+
* 配置 `props.highlightConfig.fps` 指定高亮帧率。降低帧率有利于性能。
|
|
557
|
+
#### relative fixed
|
|
558
|
+
* 配置 `props.cellFixedMode` 为 `relative` 时,将使用相对定位实现固定列与固定表头,相较于`sticky`的实现,渲染合成层更少。
|
|
558
559
|
* 问题:若开启了纵向虚拟滚动,不开启横向虚拟滚动,且不设置某些列宽时。如果纵向滚动导致某些列宽变化,则会导致右侧固定列计算错误。
|
|
560
|
+
#### tr 分层
|
|
561
|
+
* 通过css选择器将 stk-table tbody tr 配置 `transform:translateZ(0)` 对每行 tr 进行分层。在 `customCell` 较多且复杂时,尝试开启此功能可能对性能有帮助。
|
|
559
562
|
|
|
560
563
|
## Other
|
|
561
564
|
* `$*$` 兼容注释
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
### Planed removal APi
|
|
568
|
+
* `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;
|
|
@@ -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
|
};
|
|
@@ -910,12 +913,7 @@ function useVirtualScroll({
|
|
|
910
913
|
return;
|
|
911
914
|
const { offsetHeight, scrollTop } = tableContainerRef.value || {};
|
|
912
915
|
const { rowHeight } = virtualScroll.value;
|
|
913
|
-
|
|
914
|
-
if (typeof height === "number") {
|
|
915
|
-
containerHeight = height;
|
|
916
|
-
} else {
|
|
917
|
-
containerHeight = offsetHeight || DEFAULT_TABLE_HEIGHT;
|
|
918
|
-
}
|
|
916
|
+
const containerHeight = height ?? (offsetHeight || DEFAULT_TABLE_HEIGHT);
|
|
919
917
|
const { headless, headerRowHeight } = props;
|
|
920
918
|
let pageSize = Math.ceil(containerHeight / rowHeight);
|
|
921
919
|
if (!headless) {
|
|
@@ -942,17 +940,12 @@ function useVirtualScroll({
|
|
|
942
940
|
if (!virtual_on.value)
|
|
943
941
|
return;
|
|
944
942
|
let startIndex = Math.floor(sTop / rowHeight);
|
|
945
|
-
if (props.stripe) {
|
|
946
|
-
startIndex -= 1;
|
|
947
|
-
}
|
|
948
943
|
if (startIndex < 0) {
|
|
949
944
|
startIndex = 0;
|
|
950
945
|
}
|
|
951
946
|
if (props.stripe && startIndex !== 0) {
|
|
952
947
|
const scrollRows = Math.abs(oldStartIndex - startIndex);
|
|
953
|
-
if (scrollRows
|
|
954
|
-
return;
|
|
955
|
-
} else if (scrollRows % 2) {
|
|
948
|
+
if (scrollRows % 2) {
|
|
956
949
|
startIndex -= 1;
|
|
957
950
|
}
|
|
958
951
|
}
|
|
@@ -984,17 +977,18 @@ function useVirtualScroll({
|
|
|
984
977
|
if (!props.virtualX)
|
|
985
978
|
return;
|
|
986
979
|
const headerLength = (_a = tableHeaderLast.value) == null ? void 0 : _a.length;
|
|
987
|
-
const { scrollLeft } = virtualScrollX.value;
|
|
988
980
|
if (!headerLength)
|
|
989
981
|
return;
|
|
982
|
+
const { scrollLeft } = virtualScrollX.value;
|
|
990
983
|
let startIndex = 0;
|
|
991
984
|
let offsetLeft = 0;
|
|
992
985
|
let colWidthSum = 0;
|
|
993
986
|
let leftColWidthSum = 0;
|
|
987
|
+
let leftFirstColRestWidth = 0;
|
|
994
988
|
for (let colIndex = 0; colIndex < headerLength; colIndex++) {
|
|
995
|
-
startIndex++;
|
|
996
989
|
const col = tableHeaderLast.value[colIndex];
|
|
997
990
|
const colWidth = getCalculatedColWidth(col);
|
|
991
|
+
startIndex++;
|
|
998
992
|
if (col.fixed === "left") {
|
|
999
993
|
leftColWidthSum += colWidth;
|
|
1000
994
|
continue;
|
|
@@ -1003,10 +997,11 @@ function useVirtualScroll({
|
|
|
1003
997
|
if (colWidthSum >= sLeft) {
|
|
1004
998
|
offsetLeft = colWidthSum - colWidth;
|
|
1005
999
|
startIndex--;
|
|
1000
|
+
leftFirstColRestWidth = colWidthSum - sLeft;
|
|
1006
1001
|
break;
|
|
1007
1002
|
}
|
|
1008
1003
|
}
|
|
1009
|
-
colWidthSum =
|
|
1004
|
+
colWidthSum = leftFirstColRestWidth;
|
|
1010
1005
|
const containerWidth = virtualScrollX.value.containerWidth - leftColWidthSum;
|
|
1011
1006
|
let endIndex = headerLength;
|
|
1012
1007
|
for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {
|
|
@@ -1570,16 +1565,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1570
1565
|
"text-overflow": props.showOverflow,
|
|
1571
1566
|
"header-text-overflow": props.showHeaderOverflow
|
|
1572
1567
|
}]),
|
|
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
|
-
]),
|
|
1568
|
+
style: normalizeStyle({
|
|
1569
|
+
"--row-height": unref(virtualScroll).rowHeight + "px",
|
|
1570
|
+
"--header-row-height": (props.headerRowHeight || props.rowHeight) + "px",
|
|
1571
|
+
"--highlight-duration": props.highlightConfig.duration && props.highlightConfig.duration + "s",
|
|
1572
|
+
"--highlight-timing-function": unref(highlightSteps) ? `steps(${unref(highlightSteps)})` : ""
|
|
1573
|
+
}),
|
|
1583
1574
|
onScroll: onTableScroll,
|
|
1584
1575
|
onWheel: onTableWheel
|
|
1585
1576
|
}, [
|
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.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",
|
|
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",
|
|
@@ -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
|
>
|
package/src/StkTable/const.ts
CHANGED
|
@@ -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)) {
|
|
@@ -146,13 +146,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
146
146
|
if (!virtual_on.value) return;
|
|
147
147
|
const { offsetHeight, scrollTop } = tableContainerRef.value || {};
|
|
148
148
|
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
|
-
}
|
|
149
|
+
const containerHeight = height ?? (offsetHeight || DEFAULT_TABLE_HEIGHT);
|
|
156
150
|
const { headless, headerRowHeight } = props;
|
|
157
151
|
let pageSize = Math.ceil(containerHeight / rowHeight);
|
|
158
152
|
if (!headless) {
|
|
@@ -191,25 +185,19 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
191
185
|
if (!virtual_on.value) return;
|
|
192
186
|
|
|
193
187
|
let startIndex = Math.floor(sTop / rowHeight);
|
|
194
|
-
if (props.stripe) {
|
|
195
|
-
startIndex -= 1; //预渲染1行
|
|
196
|
-
}
|
|
197
188
|
if (startIndex < 0) {
|
|
198
189
|
startIndex = 0;
|
|
199
190
|
}
|
|
200
191
|
if (props.stripe && startIndex !== 0) {
|
|
201
192
|
const scrollRows = Math.abs(oldStartIndex - startIndex);
|
|
202
193
|
// 斑马纹情况下,每滚动偶数行才加载。防止斑马纹错位。
|
|
203
|
-
if (scrollRows
|
|
204
|
-
return;
|
|
205
|
-
} else if (scrollRows % 2) {
|
|
194
|
+
if (scrollRows % 2) {
|
|
206
195
|
startIndex -= 1; // 奇数-1变成偶数
|
|
207
196
|
}
|
|
208
197
|
}
|
|
209
198
|
let endIndex = startIndex + pageSize;
|
|
210
199
|
if (props.stripe) {
|
|
211
|
-
//
|
|
212
|
-
endIndex += 1;
|
|
200
|
+
endIndex += 1; // 斑马纹下多渲染一些
|
|
213
201
|
}
|
|
214
202
|
const offsetTop = startIndex * rowHeight; // startIndex之前的高度
|
|
215
203
|
endIndex = Math.min(endIndex, dataSourceCopy.value.length); // 溢出index修正
|
|
@@ -241,17 +229,22 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
241
229
|
function updateVirtualScrollX(sLeft = 0) {
|
|
242
230
|
if (!props.virtualX) return;
|
|
243
231
|
const headerLength = tableHeaderLast.value?.length;
|
|
244
|
-
const { scrollLeft } = virtualScrollX.value;
|
|
245
232
|
if (!headerLength) return;
|
|
233
|
+
|
|
234
|
+
const { scrollLeft } = virtualScrollX.value;
|
|
246
235
|
let startIndex = 0;
|
|
247
236
|
let offsetLeft = 0;
|
|
248
|
-
|
|
237
|
+
/** 列宽累加 */
|
|
249
238
|
let colWidthSum = 0;
|
|
239
|
+
/** 固定左侧列宽 */
|
|
250
240
|
let leftColWidthSum = 0;
|
|
241
|
+
/** 横向滚动时,第一列的剩余宽度 */
|
|
242
|
+
let leftFirstColRestWidth = 0;
|
|
243
|
+
|
|
251
244
|
for (let colIndex = 0; colIndex < headerLength; colIndex++) {
|
|
252
|
-
startIndex++;
|
|
253
245
|
const col = tableHeaderLast.value[colIndex];
|
|
254
246
|
const colWidth = getCalculatedColWidth(col);
|
|
247
|
+
startIndex++;
|
|
255
248
|
// fixed left 不进入计算列宽
|
|
256
249
|
if (col.fixed === 'left') {
|
|
257
250
|
leftColWidthSum += colWidth;
|
|
@@ -262,11 +255,12 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
262
255
|
if (colWidthSum >= sLeft) {
|
|
263
256
|
offsetLeft = colWidthSum - colWidth;
|
|
264
257
|
startIndex--;
|
|
258
|
+
leftFirstColRestWidth = colWidthSum - sLeft;
|
|
265
259
|
break;
|
|
266
260
|
}
|
|
267
261
|
}
|
|
268
262
|
// -----
|
|
269
|
-
colWidthSum =
|
|
263
|
+
colWidthSum = leftFirstColRestWidth;
|
|
270
264
|
const containerWidth = virtualScrollX.value.containerWidth - leftColWidthSum;
|
|
271
265
|
let endIndex = headerLength;
|
|
272
266
|
for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {
|