stk-table-vue 0.4.6 → 0.4.8
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/stk-table-vue.js +97 -93
- package/lib/style.css +7 -4
- package/package.json +64 -64
- package/src/StkTable/StkTable.vue +28 -37
- package/src/StkTable/style.less +9 -5
- package/src/StkTable/useFixedStyle.ts +3 -3
- package/src/StkTable/useKeyboardArrowScroll.ts +18 -8
- package/src/StkTable/useVirtualScroll.ts +23 -25
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ repo:
|
|
|
13
13
|
## Bug TODO:
|
|
14
14
|
* [x] props.dataSource 为 shallowRef 时,高亮行不生效。(bug:2024.02.21)(resolved:0.2.3)
|
|
15
15
|
* [] 固定列列宽拖动目标。
|
|
16
|
+
* [] 惯性滚动优化。
|
|
16
17
|
|
|
17
18
|
## Feature TODO:
|
|
18
19
|
* [x] 高亮行,单元格。
|
|
@@ -587,6 +588,8 @@ export type SortConfig<T extends Record<string, any>> = {
|
|
|
587
588
|
- 以下情况尝试开启此功能。
|
|
588
589
|
- 在 `customCell` 较多且复杂时。
|
|
589
590
|
- 大量 highlight 动画时。
|
|
591
|
+
### props.autoResize
|
|
592
|
+
* 手动设置为 `props.autoResize=false`。可取消监听的性能消耗。适用于宽度高度不变的表格。
|
|
590
593
|
|
|
591
594
|
## Tips
|
|
592
595
|
### props.fixedMode
|
package/lib/stk-table-vue.js
CHANGED
|
@@ -455,8 +455,6 @@ function useFixedStyle({
|
|
|
455
455
|
if (tagType === TagType.TD && !fixed)
|
|
456
456
|
return null;
|
|
457
457
|
const style = {};
|
|
458
|
-
const { scrollLeft, scrollWidth, offsetLeft, containerWidth } = virtualScrollX.value;
|
|
459
|
-
const scrollRight = scrollWidth - containerWidth - scrollLeft;
|
|
460
458
|
const isFixedLeft = fixed === "left";
|
|
461
459
|
if (tagType === TagType.TH) {
|
|
462
460
|
if (isRelativeMode.value) {
|
|
@@ -465,6 +463,8 @@ function useFixedStyle({
|
|
|
465
463
|
style.top = depth * props.rowHeight + "px";
|
|
466
464
|
}
|
|
467
465
|
}
|
|
466
|
+
const { scrollLeft, scrollWidth, offsetLeft, containerWidth } = virtualScrollX.value;
|
|
467
|
+
const scrollRight = scrollWidth - containerWidth - scrollLeft;
|
|
468
468
|
if (fixed === "left" || fixed === "right") {
|
|
469
469
|
if (isRelativeMode.value) {
|
|
470
470
|
if (isFixedLeft) {
|
|
@@ -740,7 +740,16 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
|
|
|
740
740
|
setHighlightDimCell
|
|
741
741
|
};
|
|
742
742
|
}
|
|
743
|
-
|
|
743
|
+
var ScrollCodes = /* @__PURE__ */ ((ScrollCodes2) => {
|
|
744
|
+
ScrollCodes2["ArrowUp"] = "ArrowUp";
|
|
745
|
+
ScrollCodes2["ArrowRight"] = "ArrowRight";
|
|
746
|
+
ScrollCodes2["ArrowDown"] = "ArrowDown";
|
|
747
|
+
ScrollCodes2["ArrowLeft"] = "ArrowLeft";
|
|
748
|
+
ScrollCodes2["PageUp"] = "PageUp";
|
|
749
|
+
ScrollCodes2["PageDown"] = "PageDown";
|
|
750
|
+
return ScrollCodes2;
|
|
751
|
+
})(ScrollCodes || {});
|
|
752
|
+
const ScrollCodesValues = Object.values(ScrollCodes);
|
|
744
753
|
function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll, virtualScrollX, tableHeaders, virtual_on }) {
|
|
745
754
|
let isMouseOver = false;
|
|
746
755
|
watch(virtual_on, (val) => {
|
|
@@ -767,7 +776,9 @@ function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll,
|
|
|
767
776
|
(_c = targetElement.value) == null ? void 0 : _c.removeEventListener("mousedown", handleMouseDown);
|
|
768
777
|
}
|
|
769
778
|
function handleKeydown(e) {
|
|
770
|
-
if (!
|
|
779
|
+
if (!virtual_on.value)
|
|
780
|
+
return;
|
|
781
|
+
if (!ScrollCodesValues.includes(e.code))
|
|
771
782
|
return;
|
|
772
783
|
if (!isMouseOver)
|
|
773
784
|
return;
|
|
@@ -777,17 +788,17 @@ function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll,
|
|
|
777
788
|
const { headless, headerRowHeight } = props;
|
|
778
789
|
const headerHeight = headless ? 0 : tableHeaders.value.length * (headerRowHeight || rowHeight);
|
|
779
790
|
const bodyPageSize = Math.floor((containerHeight - headerHeight) / rowHeight);
|
|
780
|
-
if (e.code ===
|
|
791
|
+
if (e.code === "ArrowUp") {
|
|
781
792
|
scrollTo(scrollTop - rowHeight, null);
|
|
782
|
-
} else if (e.code ===
|
|
793
|
+
} else if (e.code === "ArrowRight") {
|
|
783
794
|
scrollTo(null, scrollLeft + rowHeight);
|
|
784
|
-
} else if (e.code ===
|
|
795
|
+
} else if (e.code === "ArrowDown") {
|
|
785
796
|
scrollTo(scrollTop + rowHeight, null);
|
|
786
|
-
} else if (e.code ===
|
|
797
|
+
} else if (e.code === "ArrowLeft") {
|
|
787
798
|
scrollTo(null, scrollLeft - rowHeight);
|
|
788
|
-
} else if (e.code ===
|
|
799
|
+
} else if (e.code === "PageUp") {
|
|
789
800
|
scrollTo(scrollTop - rowHeight * bodyPageSize + headerHeight, null);
|
|
790
|
-
} else if (e.code ===
|
|
801
|
+
} else if (e.code === "PageDown") {
|
|
791
802
|
scrollTo(scrollTop + rowHeight * bodyPageSize - headerHeight, null);
|
|
792
803
|
}
|
|
793
804
|
}
|
|
@@ -937,6 +948,10 @@ function useVirtualScroll({
|
|
|
937
948
|
const { headerRowHeight } = props;
|
|
938
949
|
return headerRowHeight * tableHeaders.value.length;
|
|
939
950
|
}
|
|
951
|
+
function initVirtualScroll(height) {
|
|
952
|
+
initVirtualScrollY(height);
|
|
953
|
+
initVirtualScrollX();
|
|
954
|
+
}
|
|
940
955
|
function initVirtualScrollY(height) {
|
|
941
956
|
var _a;
|
|
942
957
|
if (height !== void 0 && typeof height !== "number") {
|
|
@@ -954,7 +969,7 @@ function useVirtualScroll({
|
|
|
954
969
|
const headerHeight = getTableHeaderHeight();
|
|
955
970
|
tableHeaderHeight.value = headerHeight;
|
|
956
971
|
if (!headless) {
|
|
957
|
-
const headerToBodyRowHeightCount = Math.floor(headerHeight
|
|
972
|
+
const headerToBodyRowHeightCount = Math.floor(headerHeight / rowHeight);
|
|
958
973
|
pageSize -= headerToBodyRowHeightCount;
|
|
959
974
|
}
|
|
960
975
|
const maxScrollTop = dataSourceCopy.value.length * rowHeight + tableHeaderHeight.value - containerHeight;
|
|
@@ -970,31 +985,21 @@ function useVirtualScroll({
|
|
|
970
985
|
virtualScrollX.value.scrollWidth = scrollWidth || DEFAULT_TABLE_WIDTH;
|
|
971
986
|
updateVirtualScrollX(scrollLeft);
|
|
972
987
|
}
|
|
973
|
-
function initVirtualScroll(height) {
|
|
974
|
-
initVirtualScrollY(height);
|
|
975
|
-
initVirtualScrollX();
|
|
976
|
-
}
|
|
977
988
|
let vue2ScrollYTimeout = null;
|
|
978
989
|
function updateVirtualScrollY(sTop = 0) {
|
|
979
|
-
const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex } = virtualScroll.value;
|
|
990
|
+
const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex, endIndex: oldEndIndex } = virtualScroll.value;
|
|
980
991
|
virtualScroll.value.scrollTop = sTop;
|
|
981
992
|
if (!virtual_on.value) {
|
|
982
993
|
return;
|
|
983
994
|
}
|
|
984
995
|
let startIndex = Math.floor(sTop / rowHeight);
|
|
985
|
-
|
|
986
|
-
startIndex = 0;
|
|
987
|
-
}
|
|
996
|
+
let endIndex = startIndex + pageSize;
|
|
988
997
|
if (props.stripe && startIndex !== 0) {
|
|
989
|
-
|
|
990
|
-
if (scrollRows % 2) {
|
|
998
|
+
if (startIndex % 2) {
|
|
991
999
|
startIndex -= 1;
|
|
992
1000
|
}
|
|
993
1001
|
}
|
|
994
|
-
|
|
995
|
-
if (props.stripe) {
|
|
996
|
-
endIndex += 1;
|
|
997
|
-
}
|
|
1002
|
+
startIndex = Math.max(0, startIndex);
|
|
998
1003
|
endIndex = Math.min(endIndex, dataSourceCopy.value.length);
|
|
999
1004
|
if (startIndex >= endIndex) {
|
|
1000
1005
|
startIndex = endIndex - pageSize;
|
|
@@ -1002,13 +1007,12 @@ function useVirtualScroll({
|
|
|
1002
1007
|
if (vue2ScrollYTimeout) {
|
|
1003
1008
|
window.clearTimeout(vue2ScrollYTimeout);
|
|
1004
1009
|
}
|
|
1010
|
+
if (oldStartIndex === startIndex && oldEndIndex === endIndex) {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1005
1013
|
const offsetTop = startIndex * rowHeight;
|
|
1006
1014
|
if (!props.optimizeVue2Scroll || sTop <= scrollTop || Math.abs(oldStartIndex - startIndex) >= pageSize) {
|
|
1007
|
-
Object.assign(virtualScroll.value, {
|
|
1008
|
-
startIndex,
|
|
1009
|
-
endIndex,
|
|
1010
|
-
offsetTop
|
|
1011
|
-
});
|
|
1015
|
+
Object.assign(virtualScroll.value, { startIndex, endIndex, offsetTop });
|
|
1012
1016
|
} else {
|
|
1013
1017
|
virtualScroll.value.endIndex = endIndex;
|
|
1014
1018
|
vue2ScrollYTimeout = window.setTimeout(() => {
|
|
@@ -1087,17 +1091,16 @@ function useVirtualScroll({
|
|
|
1087
1091
|
};
|
|
1088
1092
|
}
|
|
1089
1093
|
const _hoisted_1 = ["data-col-key", "draggable", "rowspan", "colspan", "title", "onClick"];
|
|
1090
|
-
const _hoisted_2 = {
|
|
1091
|
-
const _hoisted_3 = {
|
|
1094
|
+
const _hoisted_2 = {
|
|
1092
1095
|
key: 1,
|
|
1093
1096
|
class: "table-header-title"
|
|
1094
1097
|
};
|
|
1095
|
-
const
|
|
1096
|
-
const
|
|
1098
|
+
const _hoisted_3 = { class: "table-header-title" };
|
|
1099
|
+
const _hoisted_4 = {
|
|
1097
1100
|
key: 3,
|
|
1098
1101
|
class: "table-header-sorter"
|
|
1099
1102
|
};
|
|
1100
|
-
const
|
|
1103
|
+
const _hoisted_5 = /* @__PURE__ */ createElementVNode("svg", {
|
|
1101
1104
|
xmlns: "http://www.w3.org/2000/svg",
|
|
1102
1105
|
width: "16px",
|
|
1103
1106
|
height: "16px",
|
|
@@ -1114,31 +1117,22 @@ const _hoisted_6 = /* @__PURE__ */ createElementVNode("svg", {
|
|
|
1114
1117
|
points: "8 10 4.8 14 11.2 14"
|
|
1115
1118
|
})
|
|
1116
1119
|
], -1);
|
|
1117
|
-
const
|
|
1118
|
-
|
|
1120
|
+
const _hoisted_6 = [
|
|
1121
|
+
_hoisted_5
|
|
1119
1122
|
];
|
|
1123
|
+
const _hoisted_7 = ["onMousedown"];
|
|
1120
1124
|
const _hoisted_8 = ["onMousedown"];
|
|
1121
|
-
const _hoisted_9 =
|
|
1122
|
-
const _hoisted_10 = {
|
|
1123
|
-
key: 1,
|
|
1124
|
-
class: "virtual-top"
|
|
1125
|
-
};
|
|
1126
|
-
const _hoisted_11 = {
|
|
1125
|
+
const _hoisted_9 = {
|
|
1127
1126
|
key: 0,
|
|
1128
|
-
class: "
|
|
1127
|
+
class: "vt-x-left"
|
|
1129
1128
|
};
|
|
1130
|
-
const
|
|
1131
|
-
const
|
|
1132
|
-
const _hoisted_14 = {
|
|
1129
|
+
const _hoisted_10 = ["id", "data-row-key", "onClick", "onDblclick", "onContextmenu", "onMouseover"];
|
|
1130
|
+
const _hoisted_11 = {
|
|
1133
1131
|
key: 0,
|
|
1134
|
-
class: "
|
|
1135
|
-
};
|
|
1136
|
-
const _hoisted_15 = ["data-index", "onClick", "onMouseenter", "onMouseleave", "onMouseover"];
|
|
1137
|
-
const _hoisted_16 = ["title"];
|
|
1138
|
-
const _hoisted_17 = {
|
|
1139
|
-
key: 2,
|
|
1140
|
-
class: "virtual-bottom"
|
|
1132
|
+
class: "vt-x-left"
|
|
1141
1133
|
};
|
|
1134
|
+
const _hoisted_12 = ["data-index", "onClick", "onMouseenter", "onMouseleave", "onMouseover"];
|
|
1135
|
+
const _hoisted_13 = ["title"];
|
|
1142
1136
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
1143
1137
|
__name: "StkTable",
|
|
1144
1138
|
props: {
|
|
@@ -1283,6 +1277,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1283
1277
|
});
|
|
1284
1278
|
}
|
|
1285
1279
|
);
|
|
1280
|
+
watch(
|
|
1281
|
+
() => props.virtual,
|
|
1282
|
+
() => {
|
|
1283
|
+
nextTick(() => {
|
|
1284
|
+
initVirtualScrollY();
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
);
|
|
1286
1288
|
watch(
|
|
1287
1289
|
() => props.virtualX,
|
|
1288
1290
|
() => {
|
|
@@ -1580,15 +1582,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1580
1582
|
function setCurrentRow(rowKey, option = { silent: false }) {
|
|
1581
1583
|
if (!dataSourceCopy.value.length)
|
|
1582
1584
|
return;
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
+
const row = dataSourceCopy.value.find((it) => rowKeyGen(it) === rowKey);
|
|
1586
|
+
if (!row) {
|
|
1587
|
+
console.warn("setCurrentRow failed.rowKey:", rowKey);
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
currentRow.value = row;
|
|
1591
|
+
currentRowKey.value = rowKey;
|
|
1585
1592
|
if (!option.silent) {
|
|
1586
1593
|
emits(
|
|
1587
1594
|
"current-change",
|
|
1588
1595
|
/** no Event */
|
|
1589
1596
|
null,
|
|
1590
1597
|
currentRow.value,
|
|
1591
|
-
{ select:
|
|
1598
|
+
{ select: true }
|
|
1592
1599
|
);
|
|
1593
1600
|
}
|
|
1594
1601
|
}
|
|
@@ -1710,11 +1717,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1710
1717
|
}, [
|
|
1711
1718
|
unref(virtualX_on) ? (openBlock(), createElementBlock("th", {
|
|
1712
1719
|
key: 0,
|
|
1713
|
-
class: "
|
|
1714
|
-
style: normalizeStyle({
|
|
1715
|
-
minWidth: unref(virtualScrollX).offsetLeft + "px",
|
|
1716
|
-
width: unref(virtualScrollX).offsetLeft + "px"
|
|
1717
|
-
})
|
|
1720
|
+
class: "vt-x-left",
|
|
1721
|
+
style: normalizeStyle(`min-width:${unref(virtualScrollX).offsetLeft}px;width:${unref(virtualScrollX).offsetLeft}px`)
|
|
1718
1722
|
}, null, 4)) : createCommentVNode("", true),
|
|
1719
1723
|
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(virtualX_on) && rowIndex === tableHeaders.value.length - 1 ? unref(virtualX_columnPart) : row, (col, colIndex) => {
|
|
1720
1724
|
return openBlock(), createElementBlock("th", {
|
|
@@ -1742,65 +1746,66 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1742
1746
|
onDragover: _cache[2] || (_cache[2] = //@ts-ignore
|
|
1743
1747
|
(...args) => unref(onThDragOver) && unref(onThDragOver)(...args))
|
|
1744
1748
|
}, [
|
|
1745
|
-
createElementVNode("div",
|
|
1749
|
+
createElementVNode("div", {
|
|
1750
|
+
class: "table-header-cell-wrapper",
|
|
1751
|
+
style: normalizeStyle(`--row-span:${unref(virtualX_on) ? 1 : col.rowSpan}`)
|
|
1752
|
+
}, [
|
|
1746
1753
|
col.customHeaderCell ? (openBlock(), createBlock(resolveDynamicComponent(col.customHeaderCell), {
|
|
1747
1754
|
key: 0,
|
|
1748
1755
|
col,
|
|
1749
1756
|
colIndex,
|
|
1750
1757
|
rowIndex
|
|
1751
|
-
}, null, 8, ["col", "colIndex", "rowIndex"])) : col.type === "seq" ? (openBlock(), createElementBlock("span",
|
|
1758
|
+
}, null, 8, ["col", "colIndex", "rowIndex"])) : col.type === "seq" ? (openBlock(), createElementBlock("span", _hoisted_2, toDisplayString(col.title), 1)) : renderSlot(_ctx.$slots, "tableHeader", {
|
|
1752
1759
|
key: 2,
|
|
1753
1760
|
col
|
|
1754
1761
|
}, () => [
|
|
1755
|
-
createElementVNode("span",
|
|
1762
|
+
createElementVNode("span", _hoisted_3, toDisplayString(col.title), 1)
|
|
1756
1763
|
]),
|
|
1757
|
-
col.sorter ? (openBlock(), createElementBlock("span",
|
|
1764
|
+
col.sorter ? (openBlock(), createElementBlock("span", _hoisted_4, _hoisted_6)) : createCommentVNode("", true),
|
|
1758
1765
|
_ctx.colResizable && colIndex > 0 ? (openBlock(), createElementBlock("div", {
|
|
1759
1766
|
key: 4,
|
|
1760
1767
|
class: "table-header-resizer left",
|
|
1761
1768
|
onMousedown: (e) => unref(onThResizeMouseDown)(e, col, true)
|
|
1762
|
-
}, null, 40,
|
|
1769
|
+
}, null, 40, _hoisted_7)) : createCommentVNode("", true),
|
|
1763
1770
|
_ctx.colResizable ? (openBlock(), createElementBlock("div", {
|
|
1764
1771
|
key: 5,
|
|
1765
1772
|
class: "table-header-resizer right",
|
|
1766
1773
|
onMousedown: (e) => unref(onThResizeMouseDown)(e, col)
|
|
1767
|
-
}, null, 40,
|
|
1768
|
-
])
|
|
1774
|
+
}, null, 40, _hoisted_8)) : createCommentVNode("", true)
|
|
1775
|
+
], 4)
|
|
1769
1776
|
], 46, _hoisted_1);
|
|
1770
1777
|
}), 128)),
|
|
1771
1778
|
unref(virtualX_on) ? (openBlock(), createElementBlock("th", {
|
|
1772
1779
|
key: 1,
|
|
1773
|
-
class: "
|
|
1774
|
-
style: normalizeStyle({
|
|
1775
|
-
minWidth: unref(virtualX_offsetRight) + "px",
|
|
1776
|
-
width: unref(virtualX_offsetRight) + "px"
|
|
1777
|
-
})
|
|
1780
|
+
class: "vt-x-right",
|
|
1781
|
+
style: normalizeStyle(`min-width:${unref(virtualX_offsetRight)}px;width:${unref(virtualX_offsetRight)}px`)
|
|
1778
1782
|
}, null, 4)) : createCommentVNode("", true)
|
|
1779
1783
|
], 32);
|
|
1780
1784
|
}), 128))
|
|
1781
1785
|
], 512)) : createCommentVNode("", true),
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1786
|
+
createElementVNode("tbody", {
|
|
1787
|
+
class: normalizeClass(["stk-tbody-main", unref(virtual_on) ? "vt-on" : "vt-off"])
|
|
1788
|
+
}, [
|
|
1789
|
+
unref(virtual_on) ? (openBlock(), createElementBlock("tr", {
|
|
1790
|
+
key: 0,
|
|
1791
|
+
style: normalizeStyle(`height:${unref(virtualScroll).offsetTop}px`),
|
|
1785
1792
|
class: "padding-top-tr"
|
|
1786
1793
|
}, [
|
|
1787
|
-
unref(virtualX_on) && _ctx.fixedMode && _ctx.headless ? (openBlock(), createElementBlock("td",
|
|
1794
|
+
unref(virtualX_on) && _ctx.fixedMode && _ctx.headless ? (openBlock(), createElementBlock("td", _hoisted_9)) : createCommentVNode("", true),
|
|
1788
1795
|
_ctx.fixedMode && _ctx.headless ? (openBlock(true), createElementBlock(Fragment, { key: 1 }, renderList(unref(virtualX_columnPart), (col) => {
|
|
1789
1796
|
return openBlock(), createElementBlock("td", {
|
|
1790
1797
|
key: col.dataIndex,
|
|
1791
1798
|
style: normalizeStyle(cellStyleMap.value[unref(TagType).TD].get(colKeyGen.value(col)))
|
|
1792
1799
|
}, null, 4);
|
|
1793
1800
|
}), 128)) : createCommentVNode("", true)
|
|
1794
|
-
], 4)
|
|
1795
|
-
])) : createCommentVNode("", true),
|
|
1796
|
-
createElementVNode("tbody", _hoisted_12, [
|
|
1801
|
+
], 4)) : createCommentVNode("", true),
|
|
1797
1802
|
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(virtual_dataSourcePart), (row, rowIndex) => {
|
|
1798
1803
|
return openBlock(), createElementBlock("tr", {
|
|
1799
1804
|
id: unref(stkTableId) + "-" + (_ctx.rowKey ? rowKeyGen(row) : rowIndex),
|
|
1800
1805
|
key: _ctx.rowKey ? rowKeyGen(row) : rowIndex,
|
|
1801
1806
|
"data-row-key": _ctx.rowKey ? rowKeyGen(row) : rowIndex,
|
|
1802
1807
|
class: normalizeClass({
|
|
1803
|
-
active: _ctx.rowKey ? rowKeyGen(row) ===
|
|
1808
|
+
active: _ctx.rowKey ? rowKeyGen(row) === currentRowKey.value : row === currentRow.value,
|
|
1804
1809
|
hover: props.showTrHoverClass && (_ctx.rowKey ? rowKeyGen(row) === currentHoverRowKey.value : row === currentHoverRowKey.value),
|
|
1805
1810
|
[_ctx.rowClassName(row, rowIndex)]: true
|
|
1806
1811
|
}),
|
|
@@ -1809,7 +1814,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1809
1814
|
onContextmenu: (e) => onRowMenu(e, row),
|
|
1810
1815
|
onMouseover: (e) => onTrMouseOver(e, row)
|
|
1811
1816
|
}, [
|
|
1812
|
-
unref(virtualX_on) ? (openBlock(), createElementBlock("td",
|
|
1817
|
+
unref(virtualX_on) ? (openBlock(), createElementBlock("td", _hoisted_11)) : createCommentVNode("", true),
|
|
1813
1818
|
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(virtualX_columnPart), (col, colIndex) => {
|
|
1814
1819
|
return openBlock(), createElementBlock("td", {
|
|
1815
1820
|
key: col.dataIndex,
|
|
@@ -1838,17 +1843,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1838
1843
|
], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
1839
1844
|
createTextVNode(toDisplayString((row == null ? void 0 : row[col.dataIndex]) ?? getEmptyCellText.value(col, row)), 1)
|
|
1840
1845
|
], 64))
|
|
1841
|
-
], 8,
|
|
1842
|
-
], 46,
|
|
1846
|
+
], 8, _hoisted_13))
|
|
1847
|
+
], 46, _hoisted_12);
|
|
1843
1848
|
}), 128))
|
|
1844
|
-
], 42,
|
|
1845
|
-
}), 128))
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
])) : createCommentVNode("", true)
|
|
1849
|
+
], 42, _hoisted_10);
|
|
1850
|
+
}), 128)),
|
|
1851
|
+
unref(virtual_on) ? (openBlock(), createElementBlock("tr", {
|
|
1852
|
+
key: 1,
|
|
1853
|
+
style: normalizeStyle(`height: ${unref(virtual_offsetBottom)}px`)
|
|
1854
|
+
}, null, 4)) : createCommentVNode("", true)
|
|
1855
|
+
], 2)
|
|
1852
1856
|
], 6),
|
|
1853
1857
|
(!dataSourceCopy.value || !dataSourceCopy.value.length) && _ctx.showNoData ? (openBlock(), createElementBlock("div", {
|
|
1854
1858
|
key: 1,
|
package/lib/style.css
CHANGED
|
@@ -91,7 +91,10 @@
|
|
|
91
91
|
.stk-table.border-body-v tbody{
|
|
92
92
|
--bg-border-bottom:linear-gradient(transparent, transparent);
|
|
93
93
|
}
|
|
94
|
-
.stk-table.stripe tbody tr:nth-child(
|
|
94
|
+
.stk-table.stripe .stk-tbody-main.vt-on tr:nth-child(odd){
|
|
95
|
+
background-color:var(--stripe-bgc);
|
|
96
|
+
}
|
|
97
|
+
.stk-table.stripe .stk-tbody-main.vt-off tr:nth-child(even){
|
|
95
98
|
background-color:var(--stripe-bgc);
|
|
96
99
|
}
|
|
97
100
|
.stk-table.row-hover tbody tr:hover{
|
|
@@ -120,7 +123,7 @@
|
|
|
120
123
|
}
|
|
121
124
|
.stk-table.virtual .table-header-cell-wrapper{
|
|
122
125
|
overflow:hidden;
|
|
123
|
-
max-height:var(--header-row-height);
|
|
126
|
+
max-height:calc(var(--header-row-height) * var(--row-span));
|
|
124
127
|
}
|
|
125
128
|
.stk-table.virtual tbody td{
|
|
126
129
|
height:var(--row-height);
|
|
@@ -187,8 +190,8 @@
|
|
|
187
190
|
background-color:var(--td-bgc);
|
|
188
191
|
height:var(--row-height);
|
|
189
192
|
}
|
|
190
|
-
.stk-table .
|
|
191
|
-
.stk-table .
|
|
193
|
+
.stk-table .vt-x-left,
|
|
194
|
+
.stk-table .vt-x-right{
|
|
192
195
|
padding:0;
|
|
193
196
|
background:none;
|
|
194
197
|
pointer-events:none;
|
package/package.json
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "stk-table-vue",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"description": "Simple realtime virtual table for vue3 and vue2.7",
|
|
5
|
-
"main": "./lib/stk-table-vue.js",
|
|
6
|
-
"types": "./lib/src/StkTable/index.d.ts",
|
|
7
|
-
"packageManager": "pnpm@8.14.3",
|
|
8
|
-
"directories": {
|
|
9
|
-
"test": "test"
|
|
10
|
-
},
|
|
11
|
-
"type": "module",
|
|
12
|
-
"scripts": {
|
|
13
|
-
"dev": "vite",
|
|
14
|
-
"build": "vite build",
|
|
15
|
-
"test": "vitest"
|
|
16
|
-
},
|
|
17
|
-
"keywords": [
|
|
18
|
-
"virtual table",
|
|
19
|
-
"vue",
|
|
20
|
-
"vue2",
|
|
21
|
-
"vue3",
|
|
22
|
-
"highlight",
|
|
23
|
-
"sticky",
|
|
24
|
-
"virtual",
|
|
25
|
-
"table",
|
|
26
|
-
"list"
|
|
27
|
-
],
|
|
28
|
-
"files": [
|
|
29
|
-
"lib",
|
|
30
|
-
"src"
|
|
31
|
-
],
|
|
32
|
-
"author": "japlus",
|
|
33
|
-
"repository": {
|
|
34
|
-
"type": "git",
|
|
35
|
-
"url": "https://github.com/ja-plus/stk-table-vue"
|
|
36
|
-
},
|
|
37
|
-
"license": "MIT",
|
|
38
|
-
"devDependencies": {
|
|
39
|
-
"@types/d3-interpolate": "^3.0.4",
|
|
40
|
-
"@types/node": "^20.12.10",
|
|
41
|
-
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
|
42
|
-
"@typescript-eslint/parser": "^7.7.0",
|
|
43
|
-
"@vitejs/plugin-vue": "^5.0.4",
|
|
44
|
-
"@vue/test-utils": "2.4.4",
|
|
45
|
-
"eslint": "^8.57.0",
|
|
46
|
-
"eslint-config-prettier": "^9.1.0",
|
|
47
|
-
"eslint-plugin-html": "^8.1.0",
|
|
48
|
-
"eslint-plugin-prettier": "^5.1.3",
|
|
49
|
-
"eslint-plugin-vue": "^9.25.0",
|
|
50
|
-
"happy-dom": "^12.10.3",
|
|
51
|
-
"less": "^4.2.0",
|
|
52
|
-
"postcss-discard-comments": "^6.0.2",
|
|
53
|
-
"postcss-preset-env": "^9.5.11",
|
|
54
|
-
"prettier": "^3.2.5",
|
|
55
|
-
"typescript": "^5.4.5",
|
|
56
|
-
"vite": "^5.2.11",
|
|
57
|
-
"vite-plugin-dts": "^3.9.1",
|
|
58
|
-
"vitest": "^1.6.0",
|
|
59
|
-
"vue": "^3.4.26",
|
|
60
|
-
"vue-eslint-parser": "^9.4.2"
|
|
61
|
-
},
|
|
62
|
-
"dependencies": {
|
|
63
|
-
"d3-interpolate": "^3.0.1"
|
|
64
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "stk-table-vue",
|
|
3
|
+
"version": "0.4.8",
|
|
4
|
+
"description": "Simple realtime virtual table for vue3 and vue2.7",
|
|
5
|
+
"main": "./lib/stk-table-vue.js",
|
|
6
|
+
"types": "./lib/src/StkTable/index.d.ts",
|
|
7
|
+
"packageManager": "pnpm@8.14.3",
|
|
8
|
+
"directories": {
|
|
9
|
+
"test": "test"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"dev": "vite",
|
|
14
|
+
"build": "vite build",
|
|
15
|
+
"test": "vitest"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"virtual table",
|
|
19
|
+
"vue",
|
|
20
|
+
"vue2",
|
|
21
|
+
"vue3",
|
|
22
|
+
"highlight",
|
|
23
|
+
"sticky",
|
|
24
|
+
"virtual",
|
|
25
|
+
"table",
|
|
26
|
+
"list"
|
|
27
|
+
],
|
|
28
|
+
"files": [
|
|
29
|
+
"lib",
|
|
30
|
+
"src"
|
|
31
|
+
],
|
|
32
|
+
"author": "japlus",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/ja-plus/stk-table-vue"
|
|
36
|
+
},
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/d3-interpolate": "^3.0.4",
|
|
40
|
+
"@types/node": "^20.12.10",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
|
42
|
+
"@typescript-eslint/parser": "^7.7.0",
|
|
43
|
+
"@vitejs/plugin-vue": "^5.0.4",
|
|
44
|
+
"@vue/test-utils": "2.4.4",
|
|
45
|
+
"eslint": "^8.57.0",
|
|
46
|
+
"eslint-config-prettier": "^9.1.0",
|
|
47
|
+
"eslint-plugin-html": "^8.1.0",
|
|
48
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
49
|
+
"eslint-plugin-vue": "^9.25.0",
|
|
50
|
+
"happy-dom": "^12.10.3",
|
|
51
|
+
"less": "^4.2.0",
|
|
52
|
+
"postcss-discard-comments": "^6.0.2",
|
|
53
|
+
"postcss-preset-env": "^9.5.11",
|
|
54
|
+
"prettier": "^3.2.5",
|
|
55
|
+
"typescript": "^5.4.5",
|
|
56
|
+
"vite": "^5.2.11",
|
|
57
|
+
"vite-plugin-dts": "^3.9.1",
|
|
58
|
+
"vitest": "^1.6.0",
|
|
59
|
+
"vue": "^3.4.26",
|
|
60
|
+
"vue-eslint-parser": "^9.4.2"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"d3-interpolate": "^3.0.1"
|
|
64
|
+
}
|
|
65
65
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<!-- eslint-disable vue/attribute-hyphenation -->
|
|
1
2
|
<template>
|
|
2
3
|
<div
|
|
3
4
|
ref="tableContainerRef"
|
|
@@ -52,11 +53,8 @@
|
|
|
52
53
|
<!-- 这个th用于横向虚拟滚动表格左边距,width、maxWidth 用于兼容低版本浏览器 -->
|
|
53
54
|
<th
|
|
54
55
|
v-if="virtualX_on"
|
|
55
|
-
class="
|
|
56
|
-
:style="{
|
|
57
|
-
minWidth: virtualScrollX.offsetLeft + 'px',
|
|
58
|
-
width: virtualScrollX.offsetLeft + 'px',
|
|
59
|
-
}"
|
|
56
|
+
class="vt-x-left"
|
|
57
|
+
:style="`min-width:${virtualScrollX.offsetLeft}px;width:${virtualScrollX.offsetLeft}px`"
|
|
60
58
|
></th>
|
|
61
59
|
<!-- v for中最后一行才用 切割。TODO:不支持多级表头虚拟横向滚动 -->
|
|
62
60
|
<th
|
|
@@ -84,7 +82,7 @@
|
|
|
84
82
|
@drop="onThDrop"
|
|
85
83
|
@dragover="onThDragOver"
|
|
86
84
|
>
|
|
87
|
-
<div class="table-header-cell-wrapper">
|
|
85
|
+
<div class="table-header-cell-wrapper" :style="`--row-span:${virtualX_on ? 1 : col.rowSpan}`">
|
|
88
86
|
<component :is="col.customHeaderCell" v-if="col.customHeaderCell" :col="col" :colIndex="colIndex" :rowIndex="rowIndex" />
|
|
89
87
|
<template v-else-if="col.type === 'seq'">
|
|
90
88
|
<span class="table-header-title">{{ col.title }}</span>
|
|
@@ -116,46 +114,28 @@
|
|
|
116
114
|
</div>
|
|
117
115
|
</th>
|
|
118
116
|
<!-- 这个th用于横向虚拟滚动表格右边距 width、maxWidth 用于兼容低版本浏览器-->
|
|
119
|
-
<th
|
|
120
|
-
v-if="virtualX_on"
|
|
121
|
-
class="virtual-x-right"
|
|
122
|
-
:style="{
|
|
123
|
-
minWidth: virtualX_offsetRight + 'px',
|
|
124
|
-
width: virtualX_offsetRight + 'px',
|
|
125
|
-
}"
|
|
126
|
-
></th>
|
|
117
|
+
<th v-if="virtualX_on" class="vt-x-right" :style="`min-width:${virtualX_offsetRight}px;width:${virtualX_offsetRight}px`"></th>
|
|
127
118
|
</tr>
|
|
128
119
|
</thead>
|
|
129
120
|
|
|
130
121
|
<!-- 用于虚拟滚动表格内容定位 @deprecated 有兼容问题-->
|
|
131
|
-
<!-- <tbody v-if="virtual_on" :style="{ height: `${virtualScroll.offsetTop}px` }">
|
|
132
|
-
<!==这个tr兼容火狐==>
|
|
133
|
-
<tr></tr>
|
|
134
|
-
</tbody> -->
|
|
135
|
-
<!-- <td
|
|
136
|
-
v-for="col in virtualX_on ? virtualX_columnPart : tableHeaderLast"
|
|
137
|
-
:key="col.dataIndex"
|
|
138
|
-
class="perch-td top"
|
|
139
|
-
></td> -->
|
|
122
|
+
<!-- <tbody v-if="virtual_on" :style="{ height: `${virtualScroll.offsetTop}px` }"></tbody> -->
|
|
140
123
|
<!-- <tbody :style="{ transform: `translateY(${virtualScroll.offsetTop}px)` }"> -->
|
|
141
|
-
<tbody
|
|
142
|
-
|
|
143
|
-
<tr :style="{ height: `${virtualScroll.offsetTop}px` }" class="padding-top-tr">
|
|
124
|
+
<tbody class="stk-tbody-main" :class="virtual_on ? 'vt-on' : 'vt-off'">
|
|
125
|
+
<tr v-if="virtual_on" :style="`height:${virtualScroll.offsetTop}px`" class="padding-top-tr">
|
|
144
126
|
<!--这个td用于配合虚拟滚动的th对应,防止列错位-->
|
|
145
|
-
<td v-if="virtualX_on && fixedMode && headless" class="
|
|
127
|
+
<td v-if="virtualX_on && fixedMode && headless" class="vt-x-left"></td>
|
|
146
128
|
<template v-if="fixedMode && headless">
|
|
147
129
|
<td v-for="col in virtualX_columnPart" :key="col.dataIndex" :style="cellStyleMap[TagType.TD].get(colKeyGen(col))"></td>
|
|
148
130
|
</template>
|
|
149
131
|
</tr>
|
|
150
|
-
</tbody>
|
|
151
|
-
<tbody class="stk-tbody-main">
|
|
152
132
|
<tr
|
|
153
133
|
v-for="(row, rowIndex) in virtual_dataSourcePart"
|
|
154
134
|
:id="stkTableId + '-' + (rowKey ? rowKeyGen(row) : rowIndex)"
|
|
155
135
|
:key="rowKey ? rowKeyGen(row) : rowIndex"
|
|
156
136
|
:data-row-key="rowKey ? rowKeyGen(row) : rowIndex"
|
|
157
137
|
:class="{
|
|
158
|
-
active: rowKey ? rowKeyGen(row) ===
|
|
138
|
+
active: rowKey ? rowKeyGen(row) === currentRowKey : row === currentRow,
|
|
159
139
|
hover: props.showTrHoverClass && (rowKey ? rowKeyGen(row) === currentHoverRowKey : row === currentHoverRowKey),
|
|
160
140
|
[rowClassName(row, rowIndex)]: true,
|
|
161
141
|
}"
|
|
@@ -165,7 +145,7 @@
|
|
|
165
145
|
@mouseover="e => onTrMouseOver(e, row)"
|
|
166
146
|
>
|
|
167
147
|
<!--这个td用于配合虚拟滚动的th对应,防止列错位-->
|
|
168
|
-
<td v-if="virtualX_on" class="
|
|
148
|
+
<td v-if="virtualX_on" class="vt-x-left"></td>
|
|
169
149
|
<td
|
|
170
150
|
v-for="(col, colIndex) in virtualX_columnPart"
|
|
171
151
|
:key="col.dataIndex"
|
|
@@ -196,9 +176,7 @@
|
|
|
196
176
|
</div>
|
|
197
177
|
</td>
|
|
198
178
|
</tr>
|
|
199
|
-
|
|
200
|
-
<tbody v-if="virtual_on" class="virtual-bottom">
|
|
201
|
-
<tr :style="{ height: `${virtual_offsetBottom}px` }"></tr>
|
|
179
|
+
<tr v-if="virtual_on" :style="`height: ${virtual_offsetBottom}px`"></tr>
|
|
202
180
|
</tbody>
|
|
203
181
|
</table>
|
|
204
182
|
<div v-if="(!dataSourceCopy || !dataSourceCopy.length) && showNoData" class="stk-table-no-data" :class="{ 'no-data-full': noDataFull }">
|
|
@@ -633,6 +611,14 @@ watch(
|
|
|
633
611
|
});
|
|
634
612
|
},
|
|
635
613
|
);
|
|
614
|
+
watch(
|
|
615
|
+
() => props.virtual,
|
|
616
|
+
() => {
|
|
617
|
+
nextTick(() => {
|
|
618
|
+
initVirtualScrollY();
|
|
619
|
+
});
|
|
620
|
+
},
|
|
621
|
+
);
|
|
636
622
|
watch(
|
|
637
623
|
() => props.virtualX,
|
|
638
624
|
() => {
|
|
@@ -1036,10 +1022,15 @@ function onTrMouseOver(_e: MouseEvent, row: DT) {
|
|
|
1036
1022
|
*/
|
|
1037
1023
|
function setCurrentRow(rowKey: string, option = { silent: false }) {
|
|
1038
1024
|
if (!dataSourceCopy.value.length) return;
|
|
1039
|
-
|
|
1040
|
-
|
|
1025
|
+
const row = dataSourceCopy.value.find(it => rowKeyGen(it) === rowKey);
|
|
1026
|
+
if (!row) {
|
|
1027
|
+
console.warn('setCurrentRow failed.rowKey:', rowKey);
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
currentRow.value = row;
|
|
1031
|
+
currentRowKey.value = rowKey;
|
|
1041
1032
|
if (!option.silent) {
|
|
1042
|
-
emits('current-change', /** no Event */ null, currentRow.value, { select:
|
|
1033
|
+
emits('current-change', /** no Event */ null, currentRow.value, { select: true });
|
|
1043
1034
|
}
|
|
1044
1035
|
}
|
|
1045
1036
|
|
package/src/StkTable/style.less
CHANGED
|
@@ -134,9 +134,13 @@
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
/* 斑马纹*/
|
|
137
|
-
&.stripe {
|
|
137
|
+
&.stripe .stk-tbody-main {
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
&.vt-on tr:nth-child(odd) {
|
|
140
|
+
background-color: var(--stripe-bgc);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
&.vt-off tr:nth-child(even) {
|
|
140
144
|
background-color: var(--stripe-bgc);
|
|
141
145
|
}
|
|
142
146
|
}
|
|
@@ -183,7 +187,7 @@
|
|
|
183
187
|
/* 为不影响布局,表头行高要定死*/
|
|
184
188
|
.table-header-cell-wrapper {
|
|
185
189
|
overflow: hidden;
|
|
186
|
-
max-height: var(--header-row-height);
|
|
190
|
+
max-height: calc(var(--header-row-height) * var(--row-span));
|
|
187
191
|
}
|
|
188
192
|
|
|
189
193
|
tbody td {
|
|
@@ -279,8 +283,8 @@
|
|
|
279
283
|
}
|
|
280
284
|
|
|
281
285
|
|
|
282
|
-
.
|
|
283
|
-
.
|
|
286
|
+
.vt-x-left,
|
|
287
|
+
.vt-x-right {
|
|
284
288
|
padding: 0;
|
|
285
289
|
background: none;
|
|
286
290
|
pointer-events: none;
|
|
@@ -37,9 +37,6 @@ export function useFixedStyle<DT extends Record<string, any>>({
|
|
|
37
37
|
|
|
38
38
|
const style: CSSProperties = {};
|
|
39
39
|
|
|
40
|
-
const { scrollLeft, scrollWidth, offsetLeft, containerWidth } = virtualScrollX.value;
|
|
41
|
-
const scrollRight = scrollWidth - containerWidth - scrollLeft;
|
|
42
|
-
|
|
43
40
|
const isFixedLeft = fixed === 'left';
|
|
44
41
|
if (tagType === TagType.TH) {
|
|
45
42
|
// TH
|
|
@@ -50,6 +47,9 @@ export function useFixedStyle<DT extends Record<string, any>>({
|
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
49
|
|
|
50
|
+
const { scrollLeft, scrollWidth, offsetLeft, containerWidth } = virtualScrollX.value;
|
|
51
|
+
const scrollRight = scrollWidth - containerWidth - scrollLeft;
|
|
52
|
+
|
|
53
53
|
if (fixed === 'left' || fixed === 'right') {
|
|
54
54
|
if (isRelativeMode.value) {
|
|
55
55
|
if (isFixedLeft) {
|
|
@@ -3,7 +3,16 @@ import { StkTableColumn } from './types';
|
|
|
3
3
|
import { VirtualScrollStore, VirtualScrollXStore } from './useVirtualScroll';
|
|
4
4
|
|
|
5
5
|
/** 翻页按键 */
|
|
6
|
-
|
|
6
|
+
enum ScrollCodes {
|
|
7
|
+
ArrowUp = 'ArrowUp',
|
|
8
|
+
ArrowRight = 'ArrowRight',
|
|
9
|
+
ArrowDown = 'ArrowDown',
|
|
10
|
+
ArrowLeft = 'ArrowLeft',
|
|
11
|
+
PageUp = 'PageUp',
|
|
12
|
+
PageDown = 'PageDown',
|
|
13
|
+
}
|
|
14
|
+
/** 所有翻页按键数组 */
|
|
15
|
+
const ScrollCodesValues = Object.values(ScrollCodes);
|
|
7
16
|
|
|
8
17
|
type Options<DT extends Record<string, any>> = {
|
|
9
18
|
props: any;
|
|
@@ -52,7 +61,8 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
|
|
|
52
61
|
|
|
53
62
|
/** 键盘按下事件 */
|
|
54
63
|
function handleKeydown(e: KeyboardEvent) {
|
|
55
|
-
if (!
|
|
64
|
+
if (!virtual_on.value) return; // 非虚拟滚动使用浏览器默认滚动
|
|
65
|
+
if (!ScrollCodesValues.includes(e.code as any)) return;
|
|
56
66
|
if (!isMouseOver) return; // 不悬浮还是要触发键盘事件的
|
|
57
67
|
e.preventDefault(); // 不触发键盘默认的箭头事件
|
|
58
68
|
|
|
@@ -65,17 +75,17 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
|
|
|
65
75
|
/** 表体的page */
|
|
66
76
|
const bodyPageSize = Math.floor((containerHeight - headerHeight) / rowHeight);
|
|
67
77
|
|
|
68
|
-
if (e.code ===
|
|
78
|
+
if (e.code === ScrollCodes.ArrowUp) {
|
|
69
79
|
scrollTo(scrollTop - rowHeight, null);
|
|
70
|
-
} else if (e.code ===
|
|
80
|
+
} else if (e.code === ScrollCodes.ArrowRight) {
|
|
71
81
|
scrollTo(null, scrollLeft + rowHeight);
|
|
72
|
-
} else if (e.code ===
|
|
82
|
+
} else if (e.code === ScrollCodes.ArrowDown) {
|
|
73
83
|
scrollTo(scrollTop + rowHeight, null);
|
|
74
|
-
} else if (e.code ===
|
|
84
|
+
} else if (e.code === ScrollCodes.ArrowLeft) {
|
|
75
85
|
scrollTo(null, scrollLeft - rowHeight);
|
|
76
|
-
} else if (e.code ===
|
|
86
|
+
} else if (e.code === ScrollCodes.PageUp) {
|
|
77
87
|
scrollTo(scrollTop - rowHeight * bodyPageSize + headerHeight, null);
|
|
78
|
-
} else if (e.code ===
|
|
88
|
+
} else if (e.code === ScrollCodes.PageDown) {
|
|
79
89
|
scrollTo(scrollTop + rowHeight * bodyPageSize - headerHeight, null);
|
|
80
90
|
}
|
|
81
91
|
}
|
|
@@ -163,6 +163,15 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
163
163
|
// return theadRef.value?.offsetHeight || 0;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
+
/**
|
|
167
|
+
* 初始化虚拟滚动参数
|
|
168
|
+
* @param {number} [height] 虚拟滚动的高度
|
|
169
|
+
*/
|
|
170
|
+
function initVirtualScroll(height?: number) {
|
|
171
|
+
initVirtualScrollY(height);
|
|
172
|
+
initVirtualScrollX();
|
|
173
|
+
}
|
|
174
|
+
|
|
166
175
|
/**
|
|
167
176
|
* 初始化Y虚拟滚动参数
|
|
168
177
|
* @param {number} [height] 虚拟滚动的高度
|
|
@@ -184,7 +193,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
184
193
|
tableHeaderHeight.value = headerHeight;
|
|
185
194
|
if (!headless) {
|
|
186
195
|
/** 表头高度占几行表体高度数 */
|
|
187
|
-
const headerToBodyRowHeightCount = Math.floor(headerHeight
|
|
196
|
+
const headerToBodyRowHeightCount = Math.floor(headerHeight / rowHeight);
|
|
188
197
|
pageSize -= headerToBodyRowHeightCount; //减去表头行数
|
|
189
198
|
}
|
|
190
199
|
/** 最大的scrollTop */
|
|
@@ -203,20 +212,12 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
203
212
|
virtualScrollX.value.scrollWidth = scrollWidth || DEFAULT_TABLE_WIDTH;
|
|
204
213
|
updateVirtualScrollX(scrollLeft);
|
|
205
214
|
}
|
|
206
|
-
/**
|
|
207
|
-
* 初始化虚拟滚动参数
|
|
208
|
-
* @param {number} [height] 虚拟滚动的高度
|
|
209
|
-
*/
|
|
210
|
-
function initVirtualScroll(height?: number) {
|
|
211
|
-
initVirtualScrollY(height);
|
|
212
|
-
initVirtualScrollX();
|
|
213
|
-
}
|
|
214
215
|
|
|
215
216
|
let vue2ScrollYTimeout: null | number = null;
|
|
216
217
|
|
|
217
218
|
/** 通过滚动条位置,计算虚拟滚动的参数 */
|
|
218
219
|
function updateVirtualScrollY(sTop = 0) {
|
|
219
|
-
const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex } = virtualScroll.value;
|
|
220
|
+
const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex, endIndex: oldEndIndex } = virtualScroll.value;
|
|
220
221
|
// 先更新滚动条位置记录,其他地方有依赖。(stripe 时ArrowUp/Down滚动依赖)
|
|
221
222
|
virtualScroll.value.scrollTop = sTop;
|
|
222
223
|
|
|
@@ -226,22 +227,18 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
let startIndex = Math.floor(sTop / rowHeight);
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
230
|
+
let endIndex = startIndex + pageSize;
|
|
231
|
+
|
|
232
232
|
if (props.stripe && startIndex !== 0) {
|
|
233
|
-
const scrollRows = Math.abs(oldStartIndex - startIndex);
|
|
234
233
|
// 斑马纹情况下,每滚动偶数行才加载。防止斑马纹错位。
|
|
235
|
-
if (
|
|
234
|
+
if (startIndex % 2) {
|
|
236
235
|
startIndex -= 1; // 奇数-1变成偶数
|
|
237
236
|
}
|
|
238
237
|
}
|
|
239
|
-
let endIndex = startIndex + pageSize;
|
|
240
|
-
if (props.stripe) {
|
|
241
|
-
endIndex += 1; // 斑马纹下多渲染一些
|
|
242
|
-
}
|
|
243
238
|
|
|
244
|
-
|
|
239
|
+
startIndex = Math.max(0, startIndex);
|
|
240
|
+
|
|
241
|
+
// 溢出修正
|
|
245
242
|
endIndex = Math.min(endIndex, dataSourceCopy.value.length);
|
|
246
243
|
|
|
247
244
|
if (startIndex >= endIndex) {
|
|
@@ -253,6 +250,11 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
253
250
|
window.clearTimeout(vue2ScrollYTimeout);
|
|
254
251
|
}
|
|
255
252
|
|
|
253
|
+
if (oldStartIndex === startIndex && oldEndIndex === endIndex) {
|
|
254
|
+
// 没有变化,不需要更新
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
256
258
|
const offsetTop = startIndex * rowHeight; // startIndex之前的高度
|
|
257
259
|
|
|
258
260
|
/**
|
|
@@ -260,11 +262,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
260
262
|
*/
|
|
261
263
|
if (!props.optimizeVue2Scroll || sTop <= scrollTop || Math.abs(oldStartIndex - startIndex) >= pageSize) {
|
|
262
264
|
// 向上滚动
|
|
263
|
-
Object.assign(virtualScroll.value, {
|
|
264
|
-
startIndex,
|
|
265
|
-
endIndex,
|
|
266
|
-
offsetTop,
|
|
267
|
-
});
|
|
265
|
+
Object.assign(virtualScroll.value, { startIndex, endIndex, offsetTop });
|
|
268
266
|
} else {
|
|
269
267
|
// vue2向下滚动优化
|
|
270
268
|
virtualScroll.value.endIndex = endIndex;
|