切换tab时,恢复viewport

This commit is contained in:
2025-07-03 17:40:07 +08:00
parent ed2050c5c7
commit 44ff25b366
3 changed files with 91 additions and 23 deletions

View File

@@ -2,7 +2,7 @@
import Toolbar from './components/Toolbar.vue';
import ProjectExplorer from './components/ProjectExplorer.vue';
import ComponentsPanel from './components/flow/ComponentsPanel.vue';
import { computed, ref, onMounted, onUnmounted, onBeforeUpdate, reactive, provide, inject } from "vue";
import { computed, ref, onMounted, onUnmounted, onBeforeUpdate, reactive, provide, inject, watch } from "vue";
import { useFilesStore } from "@/ts/useStore";
import Vue3DraggableResizable from 'vue3-draggable-resizable';
import { TabPaneName, TabsPaneContext } from "element-plus";
@@ -24,6 +24,7 @@ const contentHeight = computed(() => `${windowHeight.value - toolbarHeight}px`);
const flowEditorRef = ref(null);
const flowEditorRefs = ref({});
const lastActiveFile = ref(filesStore.activeFile);
const handleTabsEdit = (
targetName: String | undefined,
@@ -85,6 +86,24 @@ const handleAddNode = (nodeData) => {
}
};
const handleSaveViewport = (viewport) => {
filesStore.updateFileViewport(filesStore.activeFile, viewport);
};
const handleRequestViewport = () => {
return filesStore.getFileViewport(filesStore.activeFile);
};
watch(
() => filesStore.activeFile,
(newVal, oldVal) => {
// 切换前保存旧 tab 的 viewport
if (oldVal && flowEditorRef.value && flowEditorRef.value.getViewport) {
const viewport = flowEditorRef.value.getViewport();
filesStore.updateFileViewport(oldVal, viewport);
}
lastActiveFile.value = newVal;
}
);
</script>
@@ -110,20 +129,20 @@ const handleAddNode = (nodeData) => {
:key="`${file.name}-${filesStore.activeFile}`"
:label="file.label"
:name="file.name.toString()"
>
/>
</el-tabs>
<div id="main-container" :style="{ height: contentHeight, overflow: 'auto' }">
<!-- 流程图编辑器 -->
<FlowEditor
:ref="(el) => { if (el) flowEditorRefs[file.name] = el }"
ref="flowEditorRef"
:height="contentHeight"
:nodes="filesStore.activeFileNodes"
:edges="filesStore.activeFileEdges"
:viewport="filesStore.getFileViewport(filesStore.activeFile)"
:key="filesStore.activeFile"
/>
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
<DialogManager />
</div>
</template>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, shallowRef, markRaw, onUnmounted } from 'vue';
import { ref, onMounted, shallowRef, markRaw, onUnmounted, watch, nextTick } from 'vue';
import { VueFlow, useVueFlow, Panel } from '@vue-flow/core';
import { Background } from '@vue-flow/background';
import { Controls } from '@vue-flow/controls';
@@ -14,13 +14,15 @@ import ImageNode from './nodes/common/ImageNode.vue';
import TextNode from './nodes/common/TextNode.vue';
import useDragAndDrop from '@/ts/useDnD';
import { useFilesStore } from '@/ts/useStore';
import type { Node, Edge, ViewportTransform } from '@vue-flow/core';
const props = defineProps({
height: {
type: String,
default: '100%'
}
});
const props = defineProps<{
height: string;
nodes: Node[];
edges: Edge[];
viewport: ViewportTransform;
}>();
const emit = defineEmits(['save-viewport', 'request-viewport']);
// 获取文件 store
const filesStore = useFilesStore();
@@ -35,12 +37,25 @@ const nodeTypes = shallowRef({
});
// 使用VueFlow的API
const { onNodesChange, onEdgesChange, onConnect, addNodes, setTransform, getViewport, updateNode } = useVueFlow({
nodes: filesStore.activeFileNodes,
edges: filesStore.activeFileEdges,
const { nodes, edges, setNodes, setEdges, setTransform, getViewport, onNodesChange, onEdgesChange, onConnect, addNodes, updateNode } = useVueFlow({
nodes: props.nodes,
edges: props.edges,
nodeTypes: nodeTypes.value
});
// 监听 viewport 变化,重绘视图
watch(
() => props.viewport,
(newViewport) => {
setTransform(newViewport);
},
{ immediate: true }
);
onMounted(() => {
setTransform(props.viewport);
});
// 监听节点变化
const handleNodesChange = (changes) => {
// 更新 store 中的节点
@@ -170,6 +185,22 @@ onUnmounted(() => {
// 移除事件监听
// document.removeEventListener('click', handleClickOutside);
});
const lastActiveFile = ref(filesStore.activeFile);
const flowEditorRef = ref();
watch(
() => filesStore.activeFile,
(newVal, oldVal) => {
// 切换前保存旧 tab 的 viewport
if (oldVal && flowEditorRef.value && flowEditorRef.value.getViewport) {
const viewport = flowEditorRef.value.getViewport();
filesStore.updateFileViewport(oldVal, viewport);
}
lastActiveFile.value = newVal;
}
);
</script>
<template>

View File

@@ -1,6 +1,6 @@
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import type { Edge, Node } from '@vue-flow/core';
import type { Edge, Node, ViewportTransform } from '@vue-flow/core';
// 文件相关的类型定义
interface FileGroup {
@@ -17,6 +17,7 @@ interface FlowFile {
groups: FileGroup[];
nodes?: Node[];
edges?: Edge[];
viewport?: { x: number; y: number; zoom: number };
}
export const useFilesStore = defineStore('files', () => {
@@ -137,6 +138,21 @@ export const useFilesStore = defineStore('files', () => {
file.nodes = nodes;
};
// 更新文件的 viewport
const updateFileViewport = (fileName: string, viewport: { x: number; y: number; zoom: number }) => {
const file = fileList.value.find(f => f.name === fileName);
if (file) file.viewport = viewport;
};
const getFileViewport = (fileName: string): ViewportTransform => {
const file = fileList.value.find(f => f.name === fileName);
const v = file?.viewport;
if (v && typeof v.x === 'number' && typeof v.y === 'number' && typeof v.zoom === 'number') {
return v as ViewportTransform;
}
return { x: 0, y: 0, zoom: 1 };
};
return {
fileList,
activeFile,
@@ -152,5 +168,7 @@ export const useFilesStore = defineStore('files', () => {
removeEdge,
updateNodePosition,
updateNodesOrder,
updateFileViewport,
getFileViewport,
};
});