20260812172705
This commit is contained in:
1 parent
1d7f7c2bba
commit
87b2d3c482
1 file changed
+60
-18
@@ -66,6 +66,8 @@ const rowEditingStates = new WeakMap();
|
||||
let activeEditingRow = null;
|
||||
let pendingEditingTarget = null;
|
||||
const pressedNavigationKeys = new Set();
|
||||
let editRequestId = 0;
|
||||
let currentTableRow = null;
|
||||
|
||||
function getRowKey(row) {
|
||||
return typeof props.rowKey === "function" ? props.rowKey(row) : row?.[props.rowKey];
|
||||
@@ -81,6 +83,18 @@ function getRowEditingState(row) {
|
||||
return state;
|
||||
}
|
||||
|
||||
// StkTable 的当前行更新会触发可见行重算。保持幂等,避免
|
||||
// activeRowKey watcher 与 editRow() 同时设置同一个行时重复刷新。
|
||||
function setCurrentRow(row) {
|
||||
if (currentTableRow === row) return;
|
||||
currentTableRow = row || null;
|
||||
tableRef.value?.setCurrentRow?.(row, { silent: true });
|
||||
}
|
||||
|
||||
function handleCurrentChange(_event, row, { select } = {}) {
|
||||
currentTableRow = select ? row : null;
|
||||
}
|
||||
|
||||
function captureEditableValues(row) {
|
||||
return new Map(
|
||||
props.columns.filter((col) => col.editor).map((col) => [col.dataIndex, row[col.dataIndex]]),
|
||||
@@ -248,10 +262,7 @@ function onColumnsUpdate(columns) {
|
||||
const real = (columns || [])
|
||||
.filter(
|
||||
(c) =>
|
||||
!isSelectionColumn(c) &&
|
||||
c.type !== "seq" &&
|
||||
c.type !== "dragRow" &&
|
||||
c.dataIndex !== "",
|
||||
!isSelectionColumn(c) && c.type !== "seq" && c.type !== "dragRow" && c.dataIndex !== "",
|
||||
)
|
||||
.map((col) => {
|
||||
const original = originalByKey.get(String(col.key ?? col.dataIndex ?? ""));
|
||||
@@ -301,18 +312,32 @@ async function scrollToRow(rowKey) {
|
||||
// 程序化激活行编辑。新增行等场景默认先滚动到目标行;行内操作可传
|
||||
// { scroll: false } 保持当前滚动位置。
|
||||
async function editRow(rowKey, focusCol = null, options = {}) {
|
||||
const requestId = ++editRequestId;
|
||||
if (options.scroll === false) await nextTick();
|
||||
else await scrollToRow(rowKey);
|
||||
if (requestId !== editRequestId) return;
|
||||
await nextTick();
|
||||
if (requestId !== editRequestId) return;
|
||||
const row = props.dataSource.find((item) => String(getRowKey(item)) === String(rowKey));
|
||||
if (!row) return;
|
||||
const table = tableRef.value;
|
||||
table?.setCurrentRow?.(row, { silent: true });
|
||||
|
||||
const now = performance.now();
|
||||
setCurrentRow(row);
|
||||
if (options.scroll === false && now - lastEditActivateAt < 150) {
|
||||
pendingEditingTarget = { row, focusCol, setAreaSelection: true };
|
||||
clearActiveEditing();
|
||||
scheduleEditActivation();
|
||||
return;
|
||||
}
|
||||
|
||||
pendingEditingTarget = null;
|
||||
clearEditActivateTimer();
|
||||
activateEditing(row, focusCol);
|
||||
lastEditActivateAt = now;
|
||||
|
||||
const focusColumn = displayColumns.value.find((column) => column.dataIndex === focusCol);
|
||||
if (focusColumn) {
|
||||
table?.setAreaSelection?.(
|
||||
tableRef.value?.setAreaSelection?.(
|
||||
{ begin: { row, col: focusColumn } },
|
||||
{ silent: true, scrollToView: false },
|
||||
);
|
||||
@@ -352,12 +377,12 @@ function clearEditActivateTimer() {
|
||||
|
||||
// 键盘导航停止(松开按键或停顿)后再激活编辑器,合并连续/按住按键,
|
||||
// 避免滚动过程中每帧创建/销毁编辑器组件导致掉帧。
|
||||
function scheduleEditActivation() {
|
||||
function scheduleEditActivation(delay = 100) {
|
||||
clearEditActivateTimer();
|
||||
editActivateTimer = setTimeout(() => {
|
||||
editActivateTimer = null;
|
||||
commitPendingEditing();
|
||||
}, 100);
|
||||
}, delay);
|
||||
}
|
||||
|
||||
function commitPendingEditing() {
|
||||
@@ -368,8 +393,19 @@ function commitPendingEditing() {
|
||||
(item) => item === target.row || String(getRowKey(item)) === String(getRowKey(target.row)),
|
||||
);
|
||||
if (row) {
|
||||
tableRef.value?.setCurrentRow?.(row, { silent: true });
|
||||
setCurrentRow(row);
|
||||
activateEditing(row, target.focusCol);
|
||||
if (target.setAreaSelection) {
|
||||
const focusColumn = displayColumns.value.find(
|
||||
(column) => column.dataIndex === target.focusCol,
|
||||
);
|
||||
if (focusColumn) {
|
||||
tableRef.value?.setAreaSelection?.(
|
||||
{ begin: { row, col: focusColumn } },
|
||||
{ silent: true, scrollToView: false },
|
||||
);
|
||||
}
|
||||
}
|
||||
lastEditActivateAt = performance.now();
|
||||
}
|
||||
}
|
||||
@@ -447,7 +483,7 @@ function handleAreaSelectionChange(ranges) {
|
||||
pendingEditingTarget = null;
|
||||
clearEditActivateTimer();
|
||||
activateEditing(row, focusCol);
|
||||
tableRef.value?.setCurrentRow?.(row, { silent: true });
|
||||
setCurrentRow(row);
|
||||
lastEditActivateAt = now;
|
||||
} else {
|
||||
pendingEditingTarget = { row, focusCol };
|
||||
@@ -457,9 +493,8 @@ function handleAreaSelectionChange(ranges) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 非键盘导航(鼠标点击等):立即激活。
|
||||
// 同一行已编辑时仍更新 focusCol(保证焦点切换到新列),
|
||||
// 但暂时禁用 select 全选(避免鼠标点击触发全选文本)。
|
||||
// 鼠标点击为离散意图操作,期望即时聚焦,不做连点合并。
|
||||
// 同一行内切换列仍立即更新 focusCol,并暂时禁用 select 全选。
|
||||
pendingEditingTarget = null;
|
||||
clearEditActivateTimer();
|
||||
if (activeEditingRow === row) {
|
||||
@@ -480,11 +515,11 @@ watch(
|
||||
rebindActiveEditingRow(props.dataSource);
|
||||
await nextTick();
|
||||
if (rowKey == null) {
|
||||
tableRef.value?.setCurrentRow?.(undefined, { silent: true });
|
||||
setCurrentRow(undefined);
|
||||
return;
|
||||
}
|
||||
const row = props.dataSource.find((item) => String(getRowKey(item)) === String(rowKey));
|
||||
tableRef.value?.setCurrentRow?.(row, { silent: true });
|
||||
setCurrentRow(row);
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
@@ -493,6 +528,7 @@ watch(
|
||||
() => props.editable,
|
||||
(editable) => {
|
||||
if (editable) return;
|
||||
editRequestId += 1;
|
||||
pendingEditingTarget = null;
|
||||
removeNavigationListeners();
|
||||
pressedNavigationKeys.clear();
|
||||
@@ -504,6 +540,7 @@ watch(
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
editRequestId += 1;
|
||||
removeNavigationListeners();
|
||||
clearEditActivateTimer();
|
||||
pressedNavigationKeys.clear();
|
||||
@@ -545,6 +582,7 @@ defineExpose({
|
||||
:show-overflow="showOverflow"
|
||||
:area-selection="editable"
|
||||
:bordered="bordered"
|
||||
@current-change="handleCurrentChange"
|
||||
@area-selection-change="handleAreaSelectionChange"
|
||||
@row-order-change="handleRowOrderChange"
|
||||
>
|
||||
@@ -591,11 +629,16 @@ defineExpose({
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.stk-table tbody tr {
|
||||
transform: translateZ(0);
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- 非 scoped 全局样式:原生 checkbox 保持低组件开销,外观使用 shadcn 语义变量。 -->
|
||||
<style lang="scss">
|
||||
.stk-table tbody tr {
|
||||
transform: translateZ(0);
|
||||
}
|
||||
/* 双类选择器 .fms-table__inner.stk-table 权重 (0,2,1) > 库默认 .stk-table (0,1,1) */
|
||||
.fms-table__inner.stk-table {
|
||||
th,
|
||||
@@ -767,7 +810,6 @@ defineExpose({
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
// actions 列按钮容器
|
||||
.fms-actions-cell {
|
||||
display: inline-flex;
|
||||
|
||||
Reference in new issue
Block a user