20260727173703

This commit is contained in:
oneao committed 2026-07-27 17:37:03 +08:00
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"
>