mirror of
https://github.com/Powerful-517/yys-editor.git
synced 2025-08-23 16:14:51 +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 Toolbar from './components/Toolbar.vue';
|
||||||
import ProjectExplorer from './components/ProjectExplorer.vue';
|
import ProjectExplorer from './components/ProjectExplorer.vue';
|
||||||
import ComponentsPanel from './components/flow/ComponentsPanel.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 { useFilesStore } from "@/ts/useStore";
|
||||||
import Vue3DraggableResizable from 'vue3-draggable-resizable';
|
import Vue3DraggableResizable from 'vue3-draggable-resizable';
|
||||||
import { TabPaneName, TabsPaneContext } from "element-plus";
|
import { TabPaneName, TabsPaneContext } from "element-plus";
|
||||||
@@ -24,6 +24,7 @@ const contentHeight = computed(() => `${windowHeight.value - toolbarHeight}px`);
|
|||||||
|
|
||||||
const flowEditorRef = ref(null);
|
const flowEditorRef = ref(null);
|
||||||
const flowEditorRefs = ref({});
|
const flowEditorRefs = ref({});
|
||||||
|
const lastActiveFile = ref(filesStore.activeFile);
|
||||||
|
|
||||||
const handleTabsEdit = (
|
const handleTabsEdit = (
|
||||||
targetName: String | undefined,
|
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>
|
</script>
|
||||||
|
|
||||||
@@ -110,20 +129,20 @@ const handleAddNode = (nodeData) => {
|
|||||||
:key="`${file.name}-${filesStore.activeFile}`"
|
:key="`${file.name}-${filesStore.activeFile}`"
|
||||||
:label="file.label"
|
:label="file.label"
|
||||||
:name="file.name.toString()"
|
:name="file.name.toString()"
|
||||||
>
|
/>
|
||||||
|
</el-tabs>
|
||||||
<div id="main-container" :style="{ height: contentHeight, overflow: 'auto' }">
|
<div id="main-container" :style="{ height: contentHeight, overflow: 'auto' }">
|
||||||
<!-- 流程图编辑器 -->
|
|
||||||
<FlowEditor
|
<FlowEditor
|
||||||
:ref="(el) => { if (el) flowEditorRefs[file.name] = el }"
|
ref="flowEditorRef"
|
||||||
:height="contentHeight"
|
:height="contentHeight"
|
||||||
|
:nodes="filesStore.activeFileNodes"
|
||||||
|
:edges="filesStore.activeFileEdges"
|
||||||
|
:viewport="filesStore.getFileViewport(filesStore.activeFile)"
|
||||||
|
:key="filesStore.activeFile"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogManager />
|
<DialogManager />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<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 { VueFlow, useVueFlow, Panel } from '@vue-flow/core';
|
||||||
import { Background } from '@vue-flow/background';
|
import { Background } from '@vue-flow/background';
|
||||||
import { Controls } from '@vue-flow/controls';
|
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 TextNode from './nodes/common/TextNode.vue';
|
||||||
import useDragAndDrop from '@/ts/useDnD';
|
import useDragAndDrop from '@/ts/useDnD';
|
||||||
import { useFilesStore } from '@/ts/useStore';
|
import { useFilesStore } from '@/ts/useStore';
|
||||||
|
import type { Node, Edge, ViewportTransform } from '@vue-flow/core';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps<{
|
||||||
height: {
|
height: string;
|
||||||
type: String,
|
nodes: Node[];
|
||||||
default: '100%'
|
edges: Edge[];
|
||||||
}
|
viewport: ViewportTransform;
|
||||||
});
|
}>();
|
||||||
|
const emit = defineEmits(['save-viewport', 'request-viewport']);
|
||||||
|
|
||||||
// 获取文件 store
|
// 获取文件 store
|
||||||
const filesStore = useFilesStore();
|
const filesStore = useFilesStore();
|
||||||
@@ -35,12 +37,25 @@ const nodeTypes = shallowRef({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 使用VueFlow的API
|
// 使用VueFlow的API
|
||||||
const { onNodesChange, onEdgesChange, onConnect, addNodes, setTransform, getViewport, updateNode } = useVueFlow({
|
const { nodes, edges, setNodes, setEdges, setTransform, getViewport, onNodesChange, onEdgesChange, onConnect, addNodes, updateNode } = useVueFlow({
|
||||||
nodes: filesStore.activeFileNodes,
|
nodes: props.nodes,
|
||||||
edges: filesStore.activeFileEdges,
|
edges: props.edges,
|
||||||
nodeTypes: nodeTypes.value
|
nodeTypes: nodeTypes.value
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 监听 viewport 变化,重绘视图
|
||||||
|
watch(
|
||||||
|
() => props.viewport,
|
||||||
|
(newViewport) => {
|
||||||
|
setTransform(newViewport);
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setTransform(props.viewport);
|
||||||
|
});
|
||||||
|
|
||||||
// 监听节点变化
|
// 监听节点变化
|
||||||
const handleNodesChange = (changes) => {
|
const handleNodesChange = (changes) => {
|
||||||
// 更新 store 中的节点
|
// 更新 store 中的节点
|
||||||
@@ -170,6 +185,22 @@ onUnmounted(() => {
|
|||||||
// 移除事件监听
|
// 移除事件监听
|
||||||
// document.removeEventListener('click', handleClickOutside);
|
// 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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import type { Edge, Node } from '@vue-flow/core';
|
import type { Edge, Node, ViewportTransform } from '@vue-flow/core';
|
||||||
|
|
||||||
// 文件相关的类型定义
|
// 文件相关的类型定义
|
||||||
interface FileGroup {
|
interface FileGroup {
|
||||||
@@ -17,6 +17,7 @@ interface FlowFile {
|
|||||||
groups: FileGroup[];
|
groups: FileGroup[];
|
||||||
nodes?: Node[];
|
nodes?: Node[];
|
||||||
edges?: Edge[];
|
edges?: Edge[];
|
||||||
|
viewport?: { x: number; y: number; zoom: number };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useFilesStore = defineStore('files', () => {
|
export const useFilesStore = defineStore('files', () => {
|
||||||
@@ -137,6 +138,21 @@ export const useFilesStore = defineStore('files', () => {
|
|||||||
file.nodes = nodes;
|
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 {
|
return {
|
||||||
fileList,
|
fileList,
|
||||||
activeFile,
|
activeFile,
|
||||||
@@ -152,5 +168,7 @@ export const useFilesStore = defineStore('files', () => {
|
|||||||
removeEdge,
|
removeEdge,
|
||||||
updateNodePosition,
|
updateNodePosition,
|
||||||
updateNodesOrder,
|
updateNodesOrder,
|
||||||
|
updateFileViewport,
|
||||||
|
getFileViewport,
|
||||||
};
|
};
|
||||||
});
|
});
|
Reference in New Issue
Block a user