mirror of
https://github.com/Powerful-517/yys-editor.git
synced 2025-08-23 08:04:50 +00:00
切换tab时,恢复viewport
This commit is contained in:
35
src/App.vue
35
src/App.vue
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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,
|
||||
};
|
||||
});
|
Reference in New Issue
Block a user