mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-09-11 22:09:47 +08:00
fix: 调整绑定关系结构,优化性能
This commit is contained in:
parent
6637fdc92b
commit
a013f35cd9
@ -362,6 +362,8 @@ export default defineComponent({
|
|||||||
disabledDragStart: props.disabledDragStart,
|
disabledDragStart: props.disabledDragStart,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
// 监听组件update
|
||||||
|
codeBlockService.addCodeRelationListener();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
},
|
},
|
||||||
|
@ -6,7 +6,12 @@
|
|||||||
type="card"
|
type="card"
|
||||||
tab-position="left"
|
tab-position="left"
|
||||||
>
|
>
|
||||||
<component :is="uiComponent.component" v-for="(config, index) in sideBarItems" :key="index" :name="config.text">
|
<component
|
||||||
|
:is="uiComponent.component"
|
||||||
|
v-for="(config, index) in sideBarItems"
|
||||||
|
:key="config.$key || index"
|
||||||
|
:name="config.text"
|
||||||
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<div :key="config.text">
|
<div :key="config.text">
|
||||||
<MIcon v-if="config.icon" :icon="config.icon"></MIcon>
|
<MIcon v-if="config.icon" :icon="config.icon"></MIcon>
|
||||||
|
@ -87,7 +87,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup name="MEditorCodeBlockList">
|
<script lang="ts" setup name="MEditorCodeBlockList">
|
||||||
import { computed, inject, reactive, ref, watch } from 'vue';
|
import { computed, inject, onMounted, reactive, ref, watch } from 'vue';
|
||||||
import { Close, Edit, Link, View } from '@element-plus/icons-vue';
|
import { Close, Edit, Link, View } from '@element-plus/icons-vue';
|
||||||
import { cloneDeep, forIn, isEmpty } from 'lodash-es';
|
import { cloneDeep, forIn, isEmpty } from 'lodash-es';
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ import { ColumnConfig } from '@tmagic/form';
|
|||||||
import { CodeBlockContent, Id } from '@tmagic/schema';
|
import { CodeBlockContent, Id } from '@tmagic/schema';
|
||||||
|
|
||||||
import Icon from '../../../components/Icon.vue';
|
import Icon from '../../../components/Icon.vue';
|
||||||
import type { CodeRelation, Services } from '../../../type';
|
import type { CodeRelation, CombineInfo, Services } from '../../../type';
|
||||||
import { CodeDeleteErrorType, CodeDslItem, ListState } from '../../../type';
|
import { CodeDeleteErrorType, CodeDslItem, ListState } from '../../../type';
|
||||||
|
|
||||||
import codeBlockEditor from './CodeBlockEditor.vue';
|
import codeBlockEditor from './CodeBlockEditor.vue';
|
||||||
@ -121,17 +121,22 @@ const isShowCodeBlockEditor = computed(() => services?.codeBlockService.getCodeE
|
|||||||
const codeCombineInfo = ref<CodeRelation | null>(null);
|
const codeCombineInfo = ref<CodeRelation | null>(null);
|
||||||
|
|
||||||
// 根据代码块ID获取其绑定的组件信息
|
// 根据代码块ID获取其绑定的组件信息
|
||||||
const getBindCompsByCodeId = (codeId: Id) => {
|
const getBindCompsByCodeId = (codeId: Id): CombineInfo[] => {
|
||||||
if (!codeCombineInfo.value || !codeCombineInfo.value[codeId]) return [];
|
if (!codeCombineInfo.value) return [];
|
||||||
const bindCompsId = Object.keys(codeCombineInfo.value[codeId]);
|
const bindsComp = [] as CombineInfo[];
|
||||||
return bindCompsId.map((compId) => ({
|
forIn(codeCombineInfo.value, (codeIds, compId) => {
|
||||||
compId,
|
if (codeIds.includes(codeId)) {
|
||||||
compName: getCompName(compId),
|
bindsComp.push({
|
||||||
}));
|
compId,
|
||||||
|
compName: getCompName(compId),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return bindsComp as CombineInfo[];
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化代码块列表
|
// 更新代码块列表
|
||||||
const initList = async () => {
|
const refreshCodeList = async () => {
|
||||||
const codeDsl = cloneDeep(await services?.codeBlockService.getCodeDsl()) || null;
|
const codeDsl = cloneDeep(await services?.codeBlockService.getCodeDsl()) || null;
|
||||||
codeCombineInfo.value = cloneDeep(services?.codeBlockService.getCombineInfo()) || null;
|
codeCombineInfo.value = cloneDeep(services?.codeBlockService.getCombineInfo()) || null;
|
||||||
if (!codeDsl || !codeCombineInfo.value) return;
|
if (!codeDsl || !codeCombineInfo.value) return;
|
||||||
@ -147,13 +152,17 @@ const initList = async () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
services?.codeBlockService.refreshAllRelations();
|
||||||
|
refreshCodeList();
|
||||||
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
[() => services?.codeBlockService.getCodeDslSync(), () => services?.codeBlockService.refreshCombineInfo()],
|
[() => services?.codeBlockService.getCodeDslSync(), () => services?.codeBlockService.getCombineInfo()],
|
||||||
() => {
|
() => {
|
||||||
initList();
|
refreshCodeList();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true,
|
|
||||||
deep: true,
|
deep: true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
import { cloneDeep, forIn, isEmpty, keys, omit, pick } from 'lodash-es';
|
import { cloneDeep, forIn, isEmpty, keys, omit, pick, union } from 'lodash-es';
|
||||||
|
|
||||||
import { CodeBlockContent, CodeBlockDSL, HookType, Id, MNode } from '@tmagic/schema';
|
import { CodeBlockContent, CodeBlockDSL, HookType, Id, MNode } from '@tmagic/schema';
|
||||||
|
|
||||||
@ -230,16 +230,39 @@ class CodeBlock extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新绑定关系
|
* 监听组件更新来更新代码块绑定关系
|
||||||
* @returns {CodeRelation | null}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
public refreshCombineInfo(): CodeRelation | null {
|
public addCodeRelationListener(): void {
|
||||||
|
// 监听组件更新
|
||||||
|
editorService.on('update', (nodes: MNode[]) => {
|
||||||
|
const relations: CodeRelation = cloneDeep(this.state.relations);
|
||||||
|
nodes.forEach((node: MNode) => {
|
||||||
|
if (node?.id) {
|
||||||
|
relations[node.id] = [];
|
||||||
|
this.getNodeRelation(node, relations);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.state.relations = { ...relations };
|
||||||
|
});
|
||||||
|
// 监听组件删除
|
||||||
|
editorService.on('remove', (nodes: MNode[]) => {
|
||||||
|
nodes.forEach((node: MNode) => {
|
||||||
|
this.state.relations = this.deleteNodeRelation(node, this.state.relations);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新全部绑定关系
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
public refreshAllRelations(): void {
|
||||||
const root = editorService.get('root');
|
const root = editorService.get('root');
|
||||||
if (!root) return null;
|
if (!root) return;
|
||||||
const relations = {};
|
const relations: CodeRelation = {};
|
||||||
this.recurseMNode(root, relations);
|
this.getNodeRelation(root, relations, true);
|
||||||
this.state.relations = relations;
|
this.state.relations = relations;
|
||||||
return this.state.relations;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -313,18 +336,6 @@ class CodeBlock extends BaseService {
|
|||||||
return await this.getUniqueId();
|
return await this.getUniqueId();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过组件id解除绑定关系(删除组件)
|
|
||||||
* @param {MNode} compId 组件节点
|
|
||||||
* @returns void
|
|
||||||
*/
|
|
||||||
public async deleteCompsInRelation(node: MNode): Promise<void> {
|
|
||||||
const codeDsl = cloneDeep(await this.getCodeDsl());
|
|
||||||
if (!codeDsl) return;
|
|
||||||
this.refreshRelationDeep(node, codeDsl);
|
|
||||||
this.setCodeDsl(codeDsl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public resetState() {
|
public resetState() {
|
||||||
this.state.isShowCodeEditor = false;
|
this.state.isShowCodeEditor = false;
|
||||||
this.state.codeDsl = null;
|
this.state.codeDsl = null;
|
||||||
@ -340,63 +351,63 @@ class CodeBlock extends BaseService {
|
|||||||
this.removeAllPlugins();
|
this.removeAllPlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除组件时 如果是容器 需要遍历删除其包含节点的绑定信息
|
|
||||||
* @param {MNode} node 节点信息
|
|
||||||
* @param {CodeBlockDSL} codeDsl 代码块
|
|
||||||
* @returns void
|
|
||||||
*/
|
|
||||||
private refreshRelationDeep(node: MNode, codeDsl: CodeBlockDSL): void {
|
|
||||||
if (!node.id) return;
|
|
||||||
forIn(codeDsl, (codeBlockContent) => {
|
|
||||||
const compsContent = codeBlockContent.comps || {};
|
|
||||||
codeBlockContent.comps = omit(compsContent, node.id);
|
|
||||||
});
|
|
||||||
if (!isEmpty(node.items)) {
|
|
||||||
node.items.forEach((item: MNode) => {
|
|
||||||
this.refreshRelationDeep(item, codeDsl);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 递归遍历dsl中挂载了代码块的节点,并更新绑定关系数据
|
* 递归遍历dsl中挂载了代码块的节点,并更新绑定关系数据
|
||||||
* @param {MContainer} node 节点信息
|
* @param {MNode} node 节点信息
|
||||||
|
* @param {CodeRelation} relation 关系数据
|
||||||
|
* @param {boolean} deep 是否深层遍历
|
||||||
* @returns void
|
* @returns void
|
||||||
*/
|
*/
|
||||||
private recurseMNode(node: MNode, relations: CodeRelation): void {
|
private getNodeRelation(node: MNode, relation: CodeRelation, deep = false): void {
|
||||||
forIn(node, (value, key) => {
|
forIn(node, (value, key) => {
|
||||||
let unConfirmedValue: MNode = { id: node.id };
|
|
||||||
if (value?.hookType === HookType.CODE && !isEmpty(value.hookData)) {
|
if (value?.hookType === HookType.CODE && !isEmpty(value.hookData)) {
|
||||||
value.hookData.forEach((relationItem: HookData) => {
|
value.hookData.forEach((relationItem: HookData) => {
|
||||||
// continue
|
if (relationItem.codeId) {
|
||||||
if (!relationItem.codeId) return;
|
relation[node.id] = union(relation[node.id], [relationItem.codeId]);
|
||||||
if (!relations[relationItem.codeId]) {
|
|
||||||
relations[relationItem.codeId] = {};
|
|
||||||
}
|
}
|
||||||
const codeItem = relations[relationItem.codeId];
|
|
||||||
if (isEmpty(codeItem[node.id])) {
|
|
||||||
codeItem[node.id] = [];
|
|
||||||
}
|
|
||||||
codeItem[node.id].push(key);
|
|
||||||
});
|
});
|
||||||
// continue
|
// continue
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (typeof value === 'object') {
|
let isContinue = false;
|
||||||
|
try {
|
||||||
|
// 只遍历更新当前组件的关系,不再深层遍历容器包含的组件
|
||||||
|
isContinue = key !== 'items' && typeof value === 'object' && JSON.stringify(value).includes('hookType');
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
if (isContinue) {
|
||||||
// 检查value内部是否有嵌套
|
// 检查value内部是否有嵌套
|
||||||
unConfirmedValue = {
|
const unConfirmedValue = {
|
||||||
...unConfirmedValue,
|
id: node.id,
|
||||||
...value,
|
...value,
|
||||||
};
|
};
|
||||||
this.recurseMNode(unConfirmedValue, relations);
|
this.getNodeRelation(unConfirmedValue, relation);
|
||||||
|
}
|
||||||
|
// 深层遍历用于代码列表初始化
|
||||||
|
if (key === 'items' && !isEmpty(value) && deep) {
|
||||||
|
value.forEach((item: MNode) => {
|
||||||
|
this.getNodeRelation(item, relation, deep);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除组件关系
|
||||||
|
* @param {MNode} node 节点信息
|
||||||
|
* @param {CodeRelation} relations 关系数据
|
||||||
|
* @returns CodeRelation
|
||||||
|
*/
|
||||||
|
private deleteNodeRelation(node: MNode, relations: CodeRelation): CodeRelation {
|
||||||
|
if (!node.id) return {};
|
||||||
|
let newRelations = omit(relations, [node.id]);
|
||||||
if (!isEmpty(node.items)) {
|
if (!isEmpty(node.items)) {
|
||||||
node.items.forEach((item: MNode) => {
|
node.items.forEach((item: MNode) => {
|
||||||
this.recurseMNode(item, relations);
|
newRelations = this.deleteNodeRelation(item, newRelations);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return newRelations;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ import { NodeType } from '@tmagic/schema';
|
|||||||
import StageCore from '@tmagic/stage';
|
import StageCore from '@tmagic/stage';
|
||||||
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
||||||
|
|
||||||
import codeBlockService from '../services/codeBlock';
|
|
||||||
import historyService from '../services/history';
|
import historyService from '../services/history';
|
||||||
import storageService, { Protocol } from '../services/storage';
|
import storageService, { Protocol } from '../services/storage';
|
||||||
import type { AddMNode, EditorNodeInfo, PastePosition, StepValue, StoreState, StoreStateKey } from '../type';
|
import type { AddMNode, EditorNodeInfo, PastePosition, StepValue, StoreState, StoreStateKey } from '../type';
|
||||||
@ -452,9 +451,6 @@ class Editor extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.addModifiedNodeId(parent.id);
|
this.addModifiedNodeId(parent.id);
|
||||||
|
|
||||||
// 通知codeBlockService解除绑定关系
|
|
||||||
codeBlockService.deleteCompsInRelation(node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -555,7 +551,6 @@ class Editor extends BaseService {
|
|||||||
this.pushHistoryState();
|
this.pushHistoryState();
|
||||||
|
|
||||||
this.emit('update', newNodes);
|
this.emit('update', newNodes);
|
||||||
codeBlockService.refreshCombineInfo();
|
|
||||||
return Array.isArray(config) ? newNodes : newNodes[0];
|
return Array.isArray(config) ? newNodes : newNodes[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,10 +351,8 @@ export type HookData = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type CodeRelation = {
|
export type CodeRelation = {
|
||||||
[codeId: Id]: {
|
/** 组件id:[代码id1,代码id2] */
|
||||||
/** 组件id:['created'] */
|
[compId: Id]: Id[];
|
||||||
[compId: Id]: string[];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface CodeDslItem {
|
export interface CodeDslItem {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user