fix: 调整绑定关系结构,优化性能

This commit is contained in:
parisma 2023-02-17 14:08:56 +08:00 committed by roymondchen
parent 6637fdc92b
commit a013f35cd9
6 changed files with 100 additions and 80 deletions

View File

@ -362,6 +362,8 @@ export default defineComponent({
disabledDragStart: props.disabledDragStart,
}),
);
// update
codeBlockService.addCodeRelationListener();
return services;
},

View File

@ -6,7 +6,12 @@
type="card"
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>
<div :key="config.text">
<MIcon v-if="config.icon" :icon="config.icon"></MIcon>

View File

@ -87,7 +87,7 @@
</template>
<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 { cloneDeep, forIn, isEmpty } from 'lodash-es';
@ -96,7 +96,7 @@ import { ColumnConfig } from '@tmagic/form';
import { CodeBlockContent, Id } from '@tmagic/schema';
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 codeBlockEditor from './CodeBlockEditor.vue';
@ -121,17 +121,22 @@ const isShowCodeBlockEditor = computed(() => services?.codeBlockService.getCodeE
const codeCombineInfo = ref<CodeRelation | null>(null);
// ID
const getBindCompsByCodeId = (codeId: Id) => {
if (!codeCombineInfo.value || !codeCombineInfo.value[codeId]) return [];
const bindCompsId = Object.keys(codeCombineInfo.value[codeId]);
return bindCompsId.map((compId) => ({
compId,
compName: getCompName(compId),
}));
const getBindCompsByCodeId = (codeId: Id): CombineInfo[] => {
if (!codeCombineInfo.value) return [];
const bindsComp = [] as CombineInfo[];
forIn(codeCombineInfo.value, (codeIds, compId) => {
if (codeIds.includes(codeId)) {
bindsComp.push({
compId,
compName: getCompName(compId),
});
}
});
return bindsComp as CombineInfo[];
};
//
const initList = async () => {
//
const refreshCodeList = async () => {
const codeDsl = cloneDeep(await services?.codeBlockService.getCodeDsl()) || null;
codeCombineInfo.value = cloneDeep(services?.codeBlockService.getCombineInfo()) || null;
if (!codeDsl || !codeCombineInfo.value) return;
@ -147,13 +152,17 @@ const initList = async () => {
});
};
onMounted(() => {
services?.codeBlockService.refreshAllRelations();
refreshCodeList();
});
watch(
[() => services?.codeBlockService.getCodeDslSync(), () => services?.codeBlockService.refreshCombineInfo()],
[() => services?.codeBlockService.getCodeDslSync(), () => services?.codeBlockService.getCombineInfo()],
() => {
initList();
refreshCodeList();
},
{
immediate: true,
deep: true,
},
);

View File

@ -17,7 +17,7 @@
*/
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';
@ -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');
if (!root) return null;
const relations = {};
this.recurseMNode(root, relations);
if (!root) return;
const relations: CodeRelation = {};
this.getNodeRelation(root, relations, true);
this.state.relations = relations;
return this.state.relations;
}
/**
@ -313,18 +336,6 @@ class CodeBlock extends BaseService {
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() {
this.state.isShowCodeEditor = false;
this.state.codeDsl = null;
@ -340,63 +351,63 @@ class CodeBlock extends BaseService {
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中挂载了代码块的节点
* @param {MContainer} node
* @param {MNode} node
* @param {CodeRelation} relation
* @param {boolean} deep
* @returns void
*/
private recurseMNode(node: MNode, relations: CodeRelation): void {
private getNodeRelation(node: MNode, relation: CodeRelation, deep = false): void {
forIn(node, (value, key) => {
let unConfirmedValue: MNode = { id: node.id };
if (value?.hookType === HookType.CODE && !isEmpty(value.hookData)) {
value.hookData.forEach((relationItem: HookData) => {
// continue
if (!relationItem.codeId) return;
if (!relations[relationItem.codeId]) {
relations[relationItem.codeId] = {};
if (relationItem.codeId) {
relation[node.id] = union(relation[node.id], [relationItem.codeId]);
}
const codeItem = relations[relationItem.codeId];
if (isEmpty(codeItem[node.id])) {
codeItem[node.id] = [];
}
codeItem[node.id].push(key);
});
// continue
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内部是否有嵌套
unConfirmedValue = {
...unConfirmedValue,
const unConfirmedValue = {
id: node.id,
...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)) {
node.items.forEach((item: MNode) => {
this.recurseMNode(item, relations);
newRelations = this.deleteNodeRelation(item, newRelations);
});
}
return newRelations;
}
}

View File

@ -24,7 +24,6 @@ import { NodeType } from '@tmagic/schema';
import StageCore from '@tmagic/stage';
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
import codeBlockService from '../services/codeBlock';
import historyService from '../services/history';
import storageService, { Protocol } from '../services/storage';
import type { AddMNode, EditorNodeInfo, PastePosition, StepValue, StoreState, StoreStateKey } from '../type';
@ -452,9 +451,6 @@ class Editor extends BaseService {
}
this.addModifiedNodeId(parent.id);
// 通知codeBlockService解除绑定关系
codeBlockService.deleteCompsInRelation(node);
}
/**
@ -555,7 +551,6 @@ class Editor extends BaseService {
this.pushHistoryState();
this.emit('update', newNodes);
codeBlockService.refreshCombineInfo();
return Array.isArray(config) ? newNodes : newNodes[0];
}

View File

@ -351,10 +351,8 @@ export type HookData = {
};
export type CodeRelation = {
[codeId: Id]: {
/** 组件id:['created'] */
[compId: Id]: string[];
};
/** 组件id:[代码id1代码id2] */
[compId: Id]: Id[];
};
export interface CodeDslItem {