stk-table-vue 1.2.0-beta.1 → 1.2.0-beta.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 +7 -2
- package/lib/index-BDlBM6WX.js +166 -0
- package/lib/src/StkTable/StkTable.vue.d.ts +8 -1
- package/lib/src/StkTable/mergeCellsCache.d.ts +3 -0
- package/lib/src/StkTable/useVirtualScroll.d.ts +1 -39
- package/lib/stk-table-vue.js +5656 -619
- package/lib/style.css +2 -1
- package/package.json +1 -1
- package/src/StkTable/StkTable.vue +23 -0
- package/src/StkTable/mergeCellsCache.ts +4 -1
- package/src/StkTable/style.less +1 -0
- package/src/StkTable/useMergeCells.ts +3 -1
- package/src/StkTable/useVirtualScroll.ts +18 -8
- package/lib/Dropdown-C1GFH7uN.js +0 -158
- package/lib/StkTable-BJu5HZzo.js +0 -5713
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ Smooth performance with tens of thousands of rows. Designed for real-time data d
|
|
|
25
25
|
- Cell highlighting with Animation API
|
|
26
26
|
- Built-in custom cells: Filter, Editable, Checkbox, Number, Change
|
|
27
27
|
- Column resize, header drag, row drag
|
|
28
|
-
- Merge cells (virtual mode supported)
|
|
28
|
+
- Merge cells (virtual mode, huge rowspan / colspan supported)
|
|
29
29
|
- Custom scrollbar
|
|
30
30
|
- Sortable & filterable
|
|
31
31
|
- Theme support (dark / light)
|
|
@@ -182,7 +182,12 @@ const dataSource = [
|
|
|
182
182
|
```
|
|
183
183
|
|
|
184
184
|
## Compare
|
|
185
|
-
Compare performance with other vue table [vue-table-
|
|
185
|
+
Compare performance with other vue table [vue-virtual-table-benchmark](https://github.com/ja-plus/vue-virtual-table-benchmark)
|
|
186
|
+
|
|
187
|
+
[Benchmark Result Page](https://ja-plus.github.io/vue-virtual-table-benchmark/perf-report.html)
|
|
188
|
+
|
|
189
|
+
## Changelog
|
|
190
|
+
[CHANGELOG](CHANGELOG.md)
|
|
186
191
|
|
|
187
192
|
|
|
188
193
|
## License
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* name: stk-table-vue
|
|
3
|
+
* version: v1.2.0-beta.2
|
|
4
|
+
* description: High performance realtime virtual table for vue3 and vue2.7
|
|
5
|
+
* author: japlus
|
|
6
|
+
* homepage: https://ja-plus.github.io/stk-table-vue/
|
|
7
|
+
* license: MIT
|
|
8
|
+
*/
|
|
9
|
+
import { defineComponent, ref, reactive, h, onMounted, onUnmounted, createElementBlock, openBlock, withModifiers, normalizeStyle, normalizeClass, createVNode, createElementVNode, nextTick } from "vue";
|
|
10
|
+
import { StkTable as _sfc_main$1 } from "./stk-table-vue.js";
|
|
11
|
+
const DROPDOWN_DEFAULT_WIDTH = 300;
|
|
12
|
+
const DROPDOWN_DEFAULT_HEIGHT = 400;
|
|
13
|
+
const PADDING = 6;
|
|
14
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
15
|
+
__name: "index",
|
|
16
|
+
setup(__props, { expose: __expose }) {
|
|
17
|
+
const theme = ref("light");
|
|
18
|
+
const checkedTempValueSet = reactive(/* @__PURE__ */ new Set());
|
|
19
|
+
const columns = ref([
|
|
20
|
+
{
|
|
21
|
+
title: "",
|
|
22
|
+
dataIndex: "value",
|
|
23
|
+
width: 30,
|
|
24
|
+
className: "stk-filter-dropdown-checkbox",
|
|
25
|
+
customCell: ({ row }) => h("input", {
|
|
26
|
+
type: "checkbox",
|
|
27
|
+
checked: checkedTempValueSet.has(row.value)
|
|
28
|
+
})
|
|
29
|
+
},
|
|
30
|
+
{ title: "", dataIndex: "label" }
|
|
31
|
+
]);
|
|
32
|
+
const visible = ref(false);
|
|
33
|
+
const position = ref({ x: 0, y: 0 });
|
|
34
|
+
const options = ref([]);
|
|
35
|
+
const dropdownEl = ref();
|
|
36
|
+
onMounted(() => {
|
|
37
|
+
document.addEventListener("click", handleClickOutside);
|
|
38
|
+
});
|
|
39
|
+
onUnmounted(() => {
|
|
40
|
+
document.removeEventListener("click", handleClickOutside);
|
|
41
|
+
});
|
|
42
|
+
let onConfirmFn;
|
|
43
|
+
function getDropdownSize() {
|
|
44
|
+
if (!dropdownEl.value) {
|
|
45
|
+
return [DROPDOWN_DEFAULT_WIDTH, DROPDOWN_DEFAULT_HEIGHT];
|
|
46
|
+
}
|
|
47
|
+
const rect = dropdownEl.value.getBoundingClientRect();
|
|
48
|
+
return [rect.width || DROPDOWN_DEFAULT_WIDTH, rect.height || DROPDOWN_DEFAULT_HEIGHT];
|
|
49
|
+
}
|
|
50
|
+
function calculatePosition(docPos) {
|
|
51
|
+
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
52
|
+
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
|
|
53
|
+
const viewportWidth = document.documentElement.clientWidth;
|
|
54
|
+
const viewportHeight = document.documentElement.clientHeight;
|
|
55
|
+
const [dropdownWidth, dropdownHeight] = getDropdownSize();
|
|
56
|
+
let finalX = docPos.x;
|
|
57
|
+
let finalY = docPos.y;
|
|
58
|
+
const relativeX = docPos.x - scrollLeft;
|
|
59
|
+
if (relativeX + dropdownWidth > viewportWidth - PADDING) {
|
|
60
|
+
finalX = viewportWidth - dropdownWidth - PADDING + scrollLeft;
|
|
61
|
+
}
|
|
62
|
+
const relativeY = docPos.y - scrollTop;
|
|
63
|
+
if (relativeY + dropdownHeight > viewportHeight - PADDING) {
|
|
64
|
+
const triggerHeight = docPos.height || 30;
|
|
65
|
+
if (relativeY - triggerHeight >= dropdownHeight + PADDING) {
|
|
66
|
+
finalY = docPos.y - triggerHeight - dropdownHeight - PADDING;
|
|
67
|
+
} else {
|
|
68
|
+
finalY = PADDING + scrollTop;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
finalX = Math.max(PADDING + scrollLeft, finalX);
|
|
72
|
+
finalY = Math.max(PADDING + scrollTop, finalY);
|
|
73
|
+
return { x: finalX, y: finalY };
|
|
74
|
+
}
|
|
75
|
+
async function show(pos, opt, onConfirm) {
|
|
76
|
+
if (dropdownEl.value) {
|
|
77
|
+
dropdownEl.value.style.visibility = "hidden";
|
|
78
|
+
}
|
|
79
|
+
visible.value = true;
|
|
80
|
+
options.value = opt || [];
|
|
81
|
+
initChecked();
|
|
82
|
+
onConfirmFn = onConfirm;
|
|
83
|
+
await nextTick();
|
|
84
|
+
position.value = calculatePosition(pos);
|
|
85
|
+
if (dropdownEl.value) {
|
|
86
|
+
dropdownEl.value.style.visibility = "visible";
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function handleClickOutside(e) {
|
|
90
|
+
var _a;
|
|
91
|
+
if (!visible.value || ((_a = dropdownEl.value) == null ? void 0 : _a.contains(e.target))) return;
|
|
92
|
+
hide();
|
|
93
|
+
}
|
|
94
|
+
function initChecked() {
|
|
95
|
+
options.value.forEach((opt) => {
|
|
96
|
+
if (opt.selected) {
|
|
97
|
+
checkedTempValueSet.add(opt.value);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function updateChecked(checked, row) {
|
|
102
|
+
if (checked) {
|
|
103
|
+
checkedTempValueSet.add(row.value);
|
|
104
|
+
} else {
|
|
105
|
+
checkedTempValueSet.delete(row.value);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function confirm() {
|
|
109
|
+
options.value.forEach((opt) => opt.selected = checkedTempValueSet.has(opt.value));
|
|
110
|
+
onConfirmFn(Array.from(checkedTempValueSet));
|
|
111
|
+
hide();
|
|
112
|
+
}
|
|
113
|
+
function hide() {
|
|
114
|
+
visible.value = false;
|
|
115
|
+
options.value = [];
|
|
116
|
+
checkedTempValueSet.clear();
|
|
117
|
+
}
|
|
118
|
+
function handleRowClick(e, row) {
|
|
119
|
+
const selected = checkedTempValueSet.has(row.value);
|
|
120
|
+
updateChecked(!selected, row);
|
|
121
|
+
}
|
|
122
|
+
function setTheme(t) {
|
|
123
|
+
theme.value = t;
|
|
124
|
+
}
|
|
125
|
+
function handleClear() {
|
|
126
|
+
checkedTempValueSet.clear();
|
|
127
|
+
confirm();
|
|
128
|
+
}
|
|
129
|
+
__expose({ visible, show, hide, setTheme });
|
|
130
|
+
return (_ctx, _cache) => {
|
|
131
|
+
return openBlock(), createElementBlock("div", {
|
|
132
|
+
ref_key: "dropdownEl",
|
|
133
|
+
ref: dropdownEl,
|
|
134
|
+
class: normalizeClass(["stk-filter-dropdown", [`stk-filter-dropdown--${theme.value}`]]),
|
|
135
|
+
style: normalizeStyle({
|
|
136
|
+
top: position.value.y + "px",
|
|
137
|
+
left: position.value.x + "px",
|
|
138
|
+
display: visible.value ? void 0 : "none"
|
|
139
|
+
}),
|
|
140
|
+
onClick: _cache[0] || (_cache[0] = withModifiers(() => {
|
|
141
|
+
}, ["stop"]))
|
|
142
|
+
}, [
|
|
143
|
+
createVNode(_sfc_main$1, {
|
|
144
|
+
"row-key": "id",
|
|
145
|
+
headless: "",
|
|
146
|
+
virtual: "",
|
|
147
|
+
"no-data-full": "",
|
|
148
|
+
theme: theme.value,
|
|
149
|
+
"row-active": false,
|
|
150
|
+
"row-height": 20,
|
|
151
|
+
bordered: false,
|
|
152
|
+
columns: columns.value,
|
|
153
|
+
"data-source": options.value,
|
|
154
|
+
onRowClick: handleRowClick
|
|
155
|
+
}, null, 8, ["theme", "columns", "data-source"]),
|
|
156
|
+
createElementVNode("footer", null, [
|
|
157
|
+
createElementVNode("button", { onClick: handleClear }, "↺"),
|
|
158
|
+
createElementVNode("button", { onClick: confirm }, "✓")
|
|
159
|
+
])
|
|
160
|
+
], 6);
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
export {
|
|
165
|
+
_sfc_main as default
|
|
166
|
+
};
|
|
@@ -242,6 +242,13 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<im
|
|
|
242
242
|
* @see {@link initVirtualScrollY}
|
|
243
243
|
*/
|
|
244
244
|
initVirtualScrollY: (height?: number) => void;
|
|
245
|
+
/**
|
|
246
|
+
* 清空 mergeCells 结果缓存并强制重算合并结果
|
|
247
|
+
*
|
|
248
|
+
* en: Clear mergeCells result cache and force recomputation
|
|
249
|
+
* @see {@link clearMergeCellsCache}
|
|
250
|
+
*/
|
|
251
|
+
clearMergeCellsCache: () => void;
|
|
245
252
|
/**
|
|
246
253
|
* 选中一行
|
|
247
254
|
*
|
|
@@ -757,13 +764,13 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<im
|
|
|
757
764
|
maxWidth: string;
|
|
758
765
|
sortConfig: SortConfig<any>;
|
|
759
766
|
colKey: UniqKeyProp;
|
|
760
|
-
rowHeight: number;
|
|
761
767
|
headless: boolean;
|
|
762
768
|
autoRowHeight: boolean | AutoRowHeightConfig<any>;
|
|
763
769
|
stripe: boolean;
|
|
764
770
|
optimizeVue2Scroll: boolean;
|
|
765
771
|
rowKey: UniqKeyProp;
|
|
766
772
|
headerRowHeight: number | string;
|
|
773
|
+
rowHeight: number;
|
|
767
774
|
scrollbar: boolean | ScrollbarOptions;
|
|
768
775
|
fixedMode: boolean;
|
|
769
776
|
theme: "light" | "dark";
|
|
@@ -15,6 +15,9 @@ export type MergeCellsResult = {
|
|
|
15
15
|
* 稳态滚动时仅新进入窗口的行会触发回调,只需在数据/列真正变化时 clear;
|
|
16
16
|
* - 条目额外保存行引用并在命中时校验同一性:即使数据被重排/替换(如排序后同一批行对象
|
|
17
17
|
* 顺序变化),也不会取到错行的旧结果,缓存清理时机不再影响正确性。
|
|
18
|
+
* - 注意:引用同一性校验无法感知行字段被原地修改(行引用不变)。
|
|
19
|
+
* 业务原地改行且 mergeCells 结果依赖该字段时,需调用 clear() 显式失效
|
|
20
|
+
* (组件已暴露 clearMergeCellsCache 实例方法)。
|
|
18
21
|
*/
|
|
19
22
|
export declare function createMergeCellsCache(): {
|
|
20
23
|
getMergeCellsResult: (row: MergeCellsParam<any>["row"], col: MergeCellsParam<any>["col"], rowIndex: number, colIndex: number) => MergeCellsResult;
|
|
@@ -50,45 +50,7 @@ export declare function useVirtualScroll(props: any, tableContainerRef: Ref<HTML
|
|
|
50
50
|
/** 全局最大 rowspan(限定跨界修正扫描范围用) */
|
|
51
51
|
getMaxRowSpanValue: () => number, scrollbarOptions: Ref<Required<ScrollbarOptions>>, isExperimentalScrollY: Ref<boolean | undefined>,
|
|
52
52
|
/** mergeCells 结果共享缓存(与 useMergeCells 共用,避免重复调用用户回调) */
|
|
53
|
-
mergeCellsCache: MergeCellsCache): readonly [
|
|
54
|
-
containerHeight: number;
|
|
55
|
-
pageSize: number;
|
|
56
|
-
startIndex: number;
|
|
57
|
-
endIndex: number;
|
|
58
|
-
rowHeight: number;
|
|
59
|
-
offsetTop: number;
|
|
60
|
-
scrollTop: number;
|
|
61
|
-
scrollHeight: number;
|
|
62
|
-
translateY: number;
|
|
63
|
-
viewportStartIndex: number;
|
|
64
|
-
viewportEndIndex: number;
|
|
65
|
-
}, VirtualScrollStore | {
|
|
66
|
-
containerHeight: number;
|
|
67
|
-
pageSize: number;
|
|
68
|
-
startIndex: number;
|
|
69
|
-
endIndex: number;
|
|
70
|
-
rowHeight: number;
|
|
71
|
-
offsetTop: number;
|
|
72
|
-
scrollTop: number;
|
|
73
|
-
scrollHeight: number;
|
|
74
|
-
translateY: number;
|
|
75
|
-
viewportStartIndex: number;
|
|
76
|
-
viewportEndIndex: number;
|
|
77
|
-
}>, Ref<{
|
|
78
|
-
containerWidth: number;
|
|
79
|
-
scrollWidth: number;
|
|
80
|
-
startIndex: number;
|
|
81
|
-
endIndex: number;
|
|
82
|
-
offsetLeft: number;
|
|
83
|
-
scrollLeft: number;
|
|
84
|
-
}, VirtualScrollXStore | {
|
|
85
|
-
containerWidth: number;
|
|
86
|
-
scrollWidth: number;
|
|
87
|
-
startIndex: number;
|
|
88
|
-
endIndex: number;
|
|
89
|
-
offsetLeft: number;
|
|
90
|
-
scrollLeft: number;
|
|
91
|
-
}>, import('vue').ComputedRef<any>, import('vue').ComputedRef<PrivateRowDT[]>, import('vue').ComputedRef<number>, import('vue').ComputedRef<any>, import('vue').ComputedRef<number>, import('vue').ComputedRef<number>, (height?: number) => void, (height?: number) => void, () => void, (sTop?: number) => void, (sLeft?: number) => void, (rowKey: UniqKey, height?: number | null) => void, () => void, () => void, import('vue').ComputedRef<PrivateStkTableColumn<PrivateRowDT>[][]>, import('vue').ComputedRef<number>, import('vue').ComputedRef<{
|
|
53
|
+
mergeCellsCache: MergeCellsCache): readonly [ShallowRef<VirtualScrollStore, VirtualScrollStore>, ShallowRef<VirtualScrollXStore, VirtualScrollXStore>, import('vue').ComputedRef<any>, import('vue').ComputedRef<PrivateRowDT[]>, import('vue').ComputedRef<number>, import('vue').ComputedRef<any>, import('vue').ComputedRef<number>, import('vue').ComputedRef<number>, (height?: number) => void, (height?: number) => void, () => void, (sTop?: number) => void, (sLeft?: number) => void, (rowKey: UniqKey, height?: number | null) => void, () => void, () => void, import('vue').ComputedRef<PrivateStkTableColumn<PrivateRowDT>[][]>, import('vue').ComputedRef<number>, import('vue').ComputedRef<{
|
|
92
54
|
startIndex: number;
|
|
93
55
|
endIndex: number;
|
|
94
56
|
offsetLeft: number;
|