♻️ Refactor cursor position cache

This commit is contained in:
2025-12-17 00:12:59 +08:00
parent 8fce8bdca4
commit 8a10b8fe0f
4 changed files with 94 additions and 36 deletions

View File

@@ -70,12 +70,11 @@ export const useDocumentStore = defineStore('document', () => {
// 在新窗口中打开文档
const openDocumentInNewWindow = async (docId: number): Promise<boolean> => {
try {
await OpenDocumentWindow(docId);
const tabStore = useTabStore();
if (tabStore.isTabsEnabled && tabStore.hasTab(docId)) {
tabStore.closeTab(docId);
}
await OpenDocumentWindow(docId);
return true;
} catch (error) {
console.error('Failed to open document in new window:', error);

View File

@@ -13,6 +13,7 @@ import {createFontExtensionFromBackend, updateFontConfig} from '@/views/editor/b
import {createStatsUpdateExtension} from '@/views/editor/basic/statsExtension';
import {createContentChangePlugin} from '@/views/editor/basic/contentChangeExtension';
import {createWheelZoomExtension} from '@/views/editor/basic/wheelZoomExtension';
import {createCursorPositionExtension, scrollToCursor} from '@/views/editor/basic/cursorPositionExtension';
import {createDynamicKeymapExtension, updateKeymapExtension} from '@/views/editor/keymap';
import {
createDynamicExtensions,
@@ -21,7 +22,7 @@ import {
setExtensionManagerView
} from '@/views/editor/manager';
import {useExtensionStore} from './extensionStore';
import createCodeBlockExtension, {blockState} from "@/views/editor/extensions/codeblock";
import createCodeBlockExtension from "@/views/editor/extensions/codeblock";
import {LruCache} from '@/common/utils/lruCache';
import {AsyncManager} from '@/common/utils/asyncManager';
import {generateContentHash} from "@/common/utils/hashUtils";
@@ -35,7 +36,7 @@ export interface DocumentStats {
selectedCharacters: number;
}
// 修复:只保存光标位置,恢复时自动滚动到光标处(更简单可靠)
// 修复:只保存光标位置,恢复时自动滚动到光标处
export interface EditorViewState {
cursorPos: number;
}
@@ -180,6 +181,9 @@ export const useEditorStore = defineStore('editor', () => {
enableAutoDetection: true
});
// 光标位置持久化扩展
const cursorPositionExtension = createCursorPositionExtension(documentId);
// 再次检查操作有效性
if (!operationManager.isOperationValid(operationId, documentId)) {
throw new Error('Operation cancelled');
@@ -212,13 +216,23 @@ export const useEditorStore = defineStore('editor', () => {
statsExtension,
contentChangeExtension,
codeBlockExtension,
cursorPositionExtension,
...dynamicExtensions,
];
// 创建编辑器状态
// 获取保存的光标位置
const savedState = documentStore.documentStates[documentId];
const docLength = content.length;
const initialCursorPos = savedState?.cursorPos !== undefined
? Math.min(savedState.cursorPos, docLength)
: docLength;
// 创建编辑器状态,设置初始光标位置
const state = EditorState.create({
doc: content,
extensions
extensions,
selection: { anchor: initialCursorPos, head: initialCursorPos }
});
return new EditorView({
@@ -316,6 +330,9 @@ export const useEditorStore = defineStore('editor', () => {
//使用 nextTick + requestAnimationFrame 确保 DOM 完全渲染
nextTick(() => {
requestAnimationFrame(() => {
// 滚动到当前光标位置
scrollToCursor(instance.view);
// 聚焦编辑器
instance.view.focus();
@@ -487,15 +504,6 @@ export const useEditorStore = defineStore('editor', () => {
await saveEditorContent(documentId);
}
// 保存光标位置
if (instance.view && instance.view.state) {
const currentState: EditorViewState = {
cursorPos: instance.view.state.selection.main.head
};
// 保存到 documentStore 用于持久化
documentStore.documentStates[documentId] = currentState;
}
// 清除自动保存定时器
instance.autoSaveTimer.clear();
@@ -578,22 +586,10 @@ export const useEditorStore = defineStore('editor', () => {
operationManager.cancelAllOperations();
editorCache.clear((_documentId, instance) => {
// 修复:清空前只保存光标位置
if (instance.view) {
const currentState: EditorViewState = {
cursorPos: instance.view.state.selection.main.head
};
// 同时保存到实例和 documentStore
instance.editorState = currentState;
documentStore.documentStates[instance.documentId] = currentState;
}
// 清除自动保存定时器
instance.autoSaveTimer.clear();
// 从扩展管理器移除
removeExtensionManagerView(instance.documentId);
// 移除DOM元素
if (instance.view.dom.parentElement) {
instance.view.dom.remove();

View File

@@ -156,10 +156,10 @@ export const useTabStore = defineStore('tab', () => {
*/
const validateTabs = () => {
const validDocIds = Object.keys(documentStore.documents).map(Number);
// 找出无效的标签页(文档已被删除)
const invalidTabIds = tabOrder.value.filter(docId => !validDocIds.includes(docId));
if (invalidTabIds.length > 0) {
// 批量清理无效标签页
invalidTabIds.forEach(docId => {
@@ -175,7 +175,7 @@ export const useTabStore = defineStore('tab', () => {
const initializeTab = () => {
// 先验证并清理无效的标签页(处理持久化的脏数据)
validateTabs();
if (isTabsEnabled.value) {
const currentDoc = documentStore.currentDocument;
if (currentDoc) {
@@ -254,7 +254,7 @@ export const useTabStore = defineStore('tab', () => {
return {
tabsMap,
tabOrder,
// 状态
tabs: readonly(tabs),
draggedTabId,
@@ -283,9 +283,5 @@ export const useTabStore = defineStore('tab', () => {
getTab
};
}, {
persist: {
key: 'voidraft-tabs',
storage: localStorage,
pick: ['tabsMap', 'tabOrder'],
},
persist: false,
});