refactor: 给Canvas解耦合

This commit is contained in:
2025-07-09 15:55:49 +08:00
parent c5ce246caf
commit 91b00a977c
7 changed files with 768 additions and 650 deletions

View File

@@ -83,7 +83,8 @@
}
">
<!-- 动态渲染组件 -->
<component :is="getComponentDefinition(component.type)" v-if="props.componentModules[component.type]"
<component :is="getComponentDefinition(component.type)"
v-if="props.componentModules[component.type] && getComponentDefinition(component.type)"
v-bind="prepareComponentProps(component.attrs || {}, component.id)" @update:bindKey="
(value: string) =>
updateComponentProp(component.id, 'bindKey', value)
@@ -98,6 +99,7 @@
<div class="flex flex-col items-center">
<div class="loading loading-spinner loading-xs mb-1"></div>
<span>Loading {{ component.type }}...</span>
<small class="mt-1 text-xs">{{ props.componentModules[component.type] ? 'Module loaded but invalid' : 'Module not found' }}</small>
</div>
</div>
</div>
@@ -159,6 +161,7 @@ import type {
} from "./diagramManager";
import { CanvasCurrentSelectedComponentID } from "../InjectKeys";
import { useComponentManager } from "./componentManager";
// 右键菜单处理函数
function handleContextMenu(e: MouseEvent) {
@@ -168,13 +171,9 @@ function handleContextMenu(e: MouseEvent) {
// 定义组件发出的事件
const emit = defineEmits([
"diagram-updated",
"component-selected",
"component-moved",
"component-delete",
"toggle-doc-panel",
"wire-created",
"wire-deleted",
"load-component-module",
"open-components",
]);
@@ -184,6 +183,12 @@ const props = defineProps<{
showDocPanel?: boolean; // 添加属性接收文档面板的显示状态
}>();
// 获取componentManager实例
const componentManager = useComponentManager();
if (!componentManager) {
throw new Error("DiagramCanvas must be used within a component manager provider");
}
// --- 画布状态 ---
const canvasContainer = ref<HTMLElement | null>(null);
const canvas = ref<HTMLElement | null>(null);
@@ -365,7 +370,13 @@ function onZoom(e: WheelEvent) {
// --- 动态组件渲染 ---
const getComponentDefinition = (type: string) => {
const module = props.componentModules[type];
if (!module) return null;
if (!module) {
console.warn(`No module found for component type: ${type}`);
// 尝试异步加载组件模块
loadComponentModule(type);
return null;
}
// 确保我们返回一个有效的组件定义
if (module.default) {
@@ -414,8 +425,12 @@ function resetComponentRefs() {
async function loadComponentModule(type: string) {
if (!props.componentModules[type]) {
try {
// 通知父组件需要加载此类型的组件
emit("load-component-module", type);
// 直接通过componentManager加载组件模块
if (componentManager) {
await componentManager.loadComponentModule(type);
// 强制更新当前组件,确保新加载的模块能被识别
console.log(`Component module ${type} loaded successfully`);
}
} catch (error) {
console.error(`Failed to request component module ${type}:`, error);
}
@@ -428,7 +443,10 @@ function handleCanvasMouseDown(e: MouseEvent) {
if (e.target === canvasContainer.value || e.target === canvas.value) {
if (selectedComponentId.value !== null) {
selectedComponentId.value = null;
emit("component-selected", null);
// 直接通过componentManager选择组件
if (componentManager) {
componentManager.selectComponent(null);
}
}
}
@@ -505,7 +523,10 @@ function startComponentDrag(e: MouseEvent, component: DiagramPart) {
// 仍然选中组件,无论是否为交互元素
if (selectedComponentId.value !== component.id) {
selectedComponentId.value = component.id;
emit("component-selected", component);
// 直接通过componentManager选择组件
if (componentManager) {
componentManager.selectComponent(component);
}
}
// 如果组件锁定位置或是交互元素,则不启动拖拽
@@ -600,12 +621,14 @@ function onComponentDrag(e: MouseEvent) {
}
}
// 通知父组件位置已更新
emit("component-moved", {
id: draggingComponentId.value,
x: Math.round(newX),
y: Math.round(newY),
});
// 通知componentManager位置已更新
if (componentManager) {
componentManager.moveComponent({
id: draggingComponentId.value,
x: Math.round(newX),
y: Math.round(newY),
});
}
// 通知图表已更新
emit("diagram-updated", diagramData.value);
@@ -634,14 +657,20 @@ function updateComponentProp(
propName: string,
value: any,
) {
diagramData.value = updatePartAttribute(
diagramData.value,
componentId,
propName,
value,
);
emit("diagram-updated", diagramData.value);
saveDiagramData(diagramData.value);
// 直接通过componentManager更新组件属性
if (componentManager) {
componentManager.updateComponentProp(componentId, propName, value);
} else {
// 后备方案:直接更新数据
diagramData.value = updatePartAttribute(
diagramData.value,
componentId,
propName,
value,
);
emit("diagram-updated", diagramData.value);
saveDiagramData(diagramData.value);
}
}
// --- 连线操作 ---
@@ -871,7 +900,10 @@ function deleteWire(wireIndex: number) {
// 删除组件
function deleteComponent(componentId: string) {
diagramData.value = deletePart(diagramData.value, componentId);
emit("component-delete", componentId);
// 直接通过componentManager删除组件
if (componentManager) {
componentManager.deleteComponent(componentId);
}
emit("diagram-updated", diagramData.value);
saveDiagramData(diagramData.value);
@@ -1024,6 +1056,24 @@ onMounted(async () => {
// 重置组件引用
resetComponentRefs();
// 设置componentManager的画布引用
if (componentManager) {
// 创建一个包含必要方法的画布API对象
const canvasAPI = {
getDiagramData: () => diagramData.value,
updateDiagramDataDirectly: (data: DiagramData) => {
diagramData.value = data;
saveDiagramData(data);
emit("diagram-updated", data);
},
getCanvasPosition: () => ({ x: position.x, y: position.y }),
getScale: () => scale.value,
$el: canvasContainer.value,
showToast
};
componentManager.setCanvasRef(canvasAPI);
}
// 加载图表数据
try {
diagramData.value = await loadDiagramData();
@@ -1039,12 +1089,10 @@ onMounted(async () => {
Array.from(componentTypes),
);
// 通知父组件需要加载组件模块
componentTypes.forEach((type) => {
if (!props.componentModules[type]) {
emit("load-component-module", type);
}
});
// 直接通过componentManager预加载组件模块
if (componentManager) {
await componentManager.preloadComponentModules(Array.from(componentTypes));
}
} catch (error) {
console.error("加载图表数据失败:", error);
}
@@ -1115,7 +1163,7 @@ function updateDiagramDataDirectly(data: DiagramData) {
emit("diagram-updated", data);
}
// 暴露方法给父组件
// 暴露方法给父组件 - 简化版本,主要用于数据访问
defineExpose({
// 基本数据操作
getDiagramData: () => diagramData.value,
@@ -1154,23 +1202,6 @@ defineExpose({
});
},
// 文件操作
openDiagramFileSelector,
exportDiagram,
// 组件操作
getSelectedComponent: () => {
if (!selectedComponentId.value) return null;
return (
diagramParts.value.find((p) => p.id === selectedComponentId.value) || null
);
},
deleteSelectedComponent: () => {
if (selectedComponentId.value) {
deleteComponent(selectedComponentId.value);
}
},
// 画布状态
getCanvasPosition: () => ({ x: position.x, y: position.y }),
getScale: () => scale.value,