feat: 实现编辑器标签页切换时恢复滚动条位置
This commit is contained in:
@@ -200,6 +200,17 @@ const handleEncodingChange = (event: Event) => {
|
||||
}
|
||||
};
|
||||
|
||||
// +++ 处理编辑器滚动事件 +++
|
||||
const handleEditorScroll = ({ scrollTop, scrollLeft }: { scrollTop: number; scrollLeft: number }) => {
|
||||
if (activeTab.value) {
|
||||
emitWorkspaceEvent('editor:updateScrollPosition', {
|
||||
tabId: activeTab.value.id,
|
||||
scrollTop,
|
||||
scrollLeft,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 注意:关闭/最小化按钮现在应该在 WorkspaceView 控制 Pane,而不是这里
|
||||
// const handleCloseContainer = () => { ... };
|
||||
@@ -338,6 +349,9 @@ const handleKeyDown = (event: KeyboardEvent) => {
|
||||
theme="vs-dark"
|
||||
class="editor-instance"
|
||||
@request-save="handleSaveRequest"
|
||||
:initialScrollTop="activeTab?.scrollTop ?? 0"
|
||||
:initialScrollLeft="activeTab?.scrollLeft ?? 0"
|
||||
@update:scrollPosition="handleEditorScroll"
|
||||
/>
|
||||
<div v-else class="editor-placeholder">{{ t('fileManager.selectFileToEdit') }}</div>
|
||||
</div>
|
||||
|
||||
@@ -46,6 +46,7 @@ const {
|
||||
closeTabsToTheRight, // 修正:移除 Global 后缀
|
||||
closeTabsToTheLeft, // 修正:移除 Global 后缀
|
||||
changeEncoding: changeGlobalEncoding, // +++ 全局编码更改 action +++
|
||||
updateTabScrollPosition, // 全局滚动位置更新 action
|
||||
} = fileEditorStore;
|
||||
|
||||
// 会话 Store Actions (用于非共享模式)
|
||||
@@ -59,6 +60,7 @@ const {
|
||||
closeTabsToTheRightInSession,
|
||||
closeTabsToTheLeftInSession,
|
||||
changeEncodingInSession, // +++ 会话编码更改 action +++
|
||||
updateTabScrollPositionInSession, // 会话滚动位置更新 action
|
||||
} = sessionStore;
|
||||
|
||||
// --- 移除本地文件状态 ---
|
||||
@@ -390,6 +392,26 @@ const handleEncodingChange = (event: Event) => {
|
||||
}
|
||||
};
|
||||
|
||||
// +++ 处理编辑器滚动事件 +++
|
||||
const handleEditorScroll = ({ scrollTop, scrollLeft }: { scrollTop: number; scrollLeft: number }) => {
|
||||
const currentActiveTab = activeTab.value;
|
||||
if (!currentActiveTab) return;
|
||||
|
||||
if (shareFileEditorTabsBoolean.value) {
|
||||
// 全局 Store
|
||||
updateTabScrollPosition(currentActiveTab.id, scrollTop, scrollLeft);
|
||||
} else {
|
||||
// 非共享模式需要 sessionId
|
||||
const sessionId = popupFileInfo.value?.sessionId;
|
||||
if (sessionId) {
|
||||
// 会话 Store
|
||||
updateTabScrollPositionInSession(sessionId, currentActiveTab.id, scrollTop, scrollLeft);
|
||||
} else {
|
||||
console.error("[FileEditorOverlay] 无法更新滚动位置:非共享模式下缺少 sessionId。");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭弹窗 (保持不变)
|
||||
const handleCloseContainer = () => {
|
||||
// 关闭前不再检查本地修改状态,因为没有本地状态了
|
||||
@@ -551,6 +573,9 @@ onBeforeUnmount(() => {
|
||||
theme="vs-dark"
|
||||
class="editor-instance"
|
||||
@request-save="handleSaveRequest"
|
||||
:initialScrollTop="activeTab?.scrollTop ?? 0"
|
||||
:initialScrollLeft="activeTab?.scrollLeft ?? 0"
|
||||
@update:scrollPosition="handleEditorScroll"
|
||||
/>
|
||||
<!-- 如果容器可见但没有活动标签页 -->
|
||||
<div v-else class="editor-placeholder">{{ t('fileManager.selectFileToEdit') }}</div>
|
||||
|
||||
@@ -9,25 +9,33 @@ import * as monaco from 'monaco-editor';
|
||||
const localFontSize = ref(14); // 本地字体大小状态,默认 14
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
language: {
|
||||
type: String,
|
||||
default: 'plaintext',
|
||||
default: 'plaintext',
|
||||
},
|
||||
theme: {
|
||||
type: String,
|
||||
default: 'vs-dark',
|
||||
default: 'vs-dark',
|
||||
},
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
initialScrollTop: { // 新增 prop
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
initialScrollLeft: { // 新增 prop
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'request-save']);
|
||||
const emit = defineEmits(['update:modelValue', 'request-save', 'update:scrollPosition']); // 新增 emit
|
||||
|
||||
const editorContainer = ref<HTMLElement | null>(null);
|
||||
let editorInstance: monaco.editor.IStandaloneCodeEditor | null = null;
|
||||
@@ -74,7 +82,30 @@ onMounted(() => {
|
||||
emit('request-save');
|
||||
},
|
||||
});
|
||||
|
||||
// 应用初始滚动位置
|
||||
if (props.initialScrollTop > 0 || props.initialScrollLeft > 0) {
|
||||
editorInstance.setScrollPosition({
|
||||
scrollTop: props.initialScrollTop,
|
||||
scrollLeft: props.initialScrollLeft,
|
||||
});
|
||||
}
|
||||
|
||||
// 监听滚动事件
|
||||
editorInstance.onDidScrollChange((e) => {
|
||||
if (editorInstance) {
|
||||
// 只有当滚动是由用户操作或实际视口变化引起时才发出
|
||||
// setScrollPosition 也会触发此事件,需要避免循环
|
||||
// 一个简单的检查是,如果事件中的滚动值与 props 中的初始值不同,则认为是有效滚动
|
||||
// 但更好的方式是父组件在设置初始值后才开始监听此事件,或此组件内部处理
|
||||
// 为简单起见,我们直接 emit
|
||||
emit('update:scrollPosition', {
|
||||
scrollTop: editorInstance.getScrollTop(),
|
||||
scrollLeft: editorInstance.getScrollLeft(),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
editorInstance.onDidChangeModelContent(() => {
|
||||
if (editorInstance) {
|
||||
|
||||
Reference in New Issue
Block a user