20260727173703
This commit is contained in:
1 parent
a8478d60ed
commit
9dbaef7787
114 files changed
+959
-2588
No files matched your search
@@ -51,12 +51,9 @@ useResizeObserver(rootRef, ([entry]) => {
|
||||
});
|
||||
|
||||
const NAVIGATION_KEYS = new Set(["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Tab"]);
|
||||
const NAVIGATION_IDLE_MS = 80;
|
||||
const rowEditingStates = new WeakMap();
|
||||
let activeEditingRow = null;
|
||||
let pendingEditingTarget = null;
|
||||
let navigationEvent = null;
|
||||
let navigationTimer = null;
|
||||
const pressedNavigationKeys = new Set();
|
||||
|
||||
function getRowKey(row) {
|
||||
@@ -232,41 +229,80 @@ function initVirtualScroll() {
|
||||
return tableRef.value?.initVirtualScroll?.();
|
||||
}
|
||||
|
||||
function clearNavigationTimer() {
|
||||
if (navigationTimer) clearTimeout(navigationTimer);
|
||||
navigationTimer = null;
|
||||
let editActivateTimer = null;
|
||||
let lastEditActivateAt = 0;
|
||||
let isRepeatNavigation = false;
|
||||
|
||||
function clearEditActivateTimer() {
|
||||
if (editActivateTimer) {
|
||||
clearTimeout(editActivateTimer);
|
||||
editActivateTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 键盘导航停止(松开按键或停顿)后再激活编辑器,合并连续/按住按键,
|
||||
// 避免滚动过程中每帧创建/销毁编辑器组件导致掉帧。
|
||||
function scheduleEditActivation() {
|
||||
clearEditActivateTimer();
|
||||
editActivateTimer = setTimeout(() => {
|
||||
editActivateTimer = null;
|
||||
commitPendingEditing();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function commitPendingEditing() {
|
||||
clearNavigationTimer();
|
||||
const target = pendingEditingTarget;
|
||||
pendingEditingTarget = null;
|
||||
if (!target) return;
|
||||
const row = props.dataSource.find(
|
||||
(item) => item === target.row || String(getRowKey(item)) === String(getRowKey(target.row)),
|
||||
);
|
||||
if (row) activateEditing(row, target.focusCol);
|
||||
if (row) {
|
||||
activateEditing(row, target.focusCol);
|
||||
lastEditActivateAt = performance.now();
|
||||
}
|
||||
}
|
||||
|
||||
function schedulePendingEditing() {
|
||||
clearNavigationTimer();
|
||||
navigationTimer = setTimeout(commitPendingEditing, NAVIGATION_IDLE_MS);
|
||||
function removeNavigationListeners() {
|
||||
window.removeEventListener("keyup", handleKeyupCapture, true);
|
||||
window.removeEventListener("blur", handleWindowBlur);
|
||||
}
|
||||
|
||||
function handleKeydownCapture(event) {
|
||||
if (!NAVIGATION_KEYS.has(event.key)) return;
|
||||
if (!pressedNavigationKeys.size) {
|
||||
window.addEventListener("keyup", handleKeyupCapture, true);
|
||||
window.addEventListener("blur", handleWindowBlur);
|
||||
}
|
||||
pressedNavigationKeys.add(event.key);
|
||||
const currentEvent = { repeat: event.repeat };
|
||||
navigationEvent = currentEvent;
|
||||
queueMicrotask(() => {
|
||||
if (navigationEvent === currentEvent) navigationEvent = null;
|
||||
});
|
||||
// event.repeat=true 表示系统自动重复(按住方向键不松),用于区分“按住滚动”与“离散点按”
|
||||
if (event.repeat) isRepeatNavigation = true;
|
||||
}
|
||||
|
||||
function handleKeyupCapture(event) {
|
||||
if (!NAVIGATION_KEYS.has(event.key)) return;
|
||||
pressedNavigationKeys.delete(event.key);
|
||||
if (!pressedNavigationKeys.size) commitPendingEditing();
|
||||
if (!pressedNavigationKeys.delete(event.key) || pressedNavigationKeys.size) return;
|
||||
|
||||
removeNavigationListeners();
|
||||
|
||||
if (isRepeatNavigation) {
|
||||
// 长按已经结束,立即恢复最终目标行,不再额外等待防抖时间。
|
||||
isRepeatNavigation = false;
|
||||
clearEditActivateTimer();
|
||||
commitPendingEditing();
|
||||
return;
|
||||
}
|
||||
|
||||
// 快速离散连按仍使用短防抖,避免连续挂载/卸载整行编辑器。
|
||||
if (pendingEditingTarget) scheduleEditActivation();
|
||||
}
|
||||
|
||||
function handleWindowBlur() {
|
||||
removeNavigationListeners();
|
||||
pressedNavigationKeys.clear();
|
||||
isRepeatNavigation = false;
|
||||
clearEditActivateTimer();
|
||||
commitPendingEditing();
|
||||
}
|
||||
|
||||
// 选区变化后,目标行进入编辑,活动单元格获得焦点。
|
||||
@@ -278,22 +314,41 @@ function handleAreaSelectionChange(ranges) {
|
||||
const col = target ? displayColumns.value[target.col] : null;
|
||||
if (!row) {
|
||||
pendingEditingTarget = null;
|
||||
clearNavigationTimer();
|
||||
clearActiveEditing();
|
||||
clearEditActivateTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
const focusCol = col?.editor ? col.dataIndex : null;
|
||||
if (navigationEvent?.repeat) {
|
||||
pendingEditingTarget = { row, focusCol };
|
||||
clearActiveEditing();
|
||||
schedulePendingEditing();
|
||||
// 键盘导航期间(按下方向键等):
|
||||
// - 按住方向键滚动(event.repeat=true):全程保持 0 编辑器,避免长按下反复创建组件导致卡顿/闪烁;
|
||||
// 松手后再激活到最终行。
|
||||
// - 慢速离散点按(非 repeat):立即激活,编辑器逐行跟随、跟手;
|
||||
// - 快速连按(间隔 <150ms):防抖合并,避免连按时每键挂载掉帧。
|
||||
if (pressedNavigationKeys.size > 0) {
|
||||
if (isRepeatNavigation) {
|
||||
pendingEditingTarget = { row, focusCol };
|
||||
clearActiveEditing();
|
||||
} else {
|
||||
const now = performance.now();
|
||||
if (now - lastEditActivateAt >= 150) {
|
||||
pendingEditingTarget = null;
|
||||
clearEditActivateTimer();
|
||||
activateEditing(row, focusCol);
|
||||
lastEditActivateAt = now;
|
||||
} else {
|
||||
pendingEditingTarget = { row, focusCol };
|
||||
scheduleEditActivation();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 非键盘导航(鼠标点击等):立即激活
|
||||
pendingEditingTarget = null;
|
||||
clearNavigationTimer();
|
||||
clearEditActivateTimer();
|
||||
activateEditing(row, focusCol);
|
||||
lastEditActivateAt = performance.now();
|
||||
}
|
||||
|
||||
watch(
|
||||
@@ -316,15 +371,19 @@ watch(
|
||||
(editable) => {
|
||||
if (editable) return;
|
||||
pendingEditingTarget = null;
|
||||
removeNavigationListeners();
|
||||
pressedNavigationKeys.clear();
|
||||
clearNavigationTimer();
|
||||
isRepeatNavigation = false;
|
||||
clearEditActivateTimer();
|
||||
clearActiveEditing();
|
||||
tableRef.value?.clearSelectedArea?.();
|
||||
},
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
removeNavigationListeners();
|
||||
clearEditActivateTimer();
|
||||
pressedNavigationKeys.clear();
|
||||
clearNavigationTimer();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
@@ -338,12 +397,7 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
ref="rootRef"
|
||||
class="fms-table"
|
||||
@keydown.capture="handleKeydownCapture"
|
||||
@keyup.capture="handleKeyupCapture"
|
||||
>
|
||||
<div ref="rootRef" class="fms-table" @keydown.capture="handleKeydownCapture">
|
||||
<StkTable
|
||||
ref="tableRef"
|
||||
class="fms-table__inner"
|
||||
@@ -363,7 +417,7 @@ defineExpose({
|
||||
:bordered="bordered"
|
||||
:no-data-full="noDataFull"
|
||||
:show-overflow="showOverflow"
|
||||
:area-selection="true"
|
||||
:area-selection="editable"
|
||||
@area-selection-change="handleAreaSelectionChange"
|
||||
@row-order-change="handleRowOrderChange"
|
||||
>
|
||||
|
||||
Reference in new issue
Block a user