mirror of
				https://github.com/Tencent/tmagic-editor.git
				synced 2025-11-04 02:28:04 +08:00 
			
		
		
		
	fix: 调整绑定关系结构,优化性能
This commit is contained in:
		
							parent
							
								
									6637fdc92b
								
							
						
					
					
						commit
						a013f35cd9
					
				@ -362,6 +362,8 @@ export default defineComponent({
 | 
			
		||||
        disabledDragStart: props.disabledDragStart,
 | 
			
		||||
      }),
 | 
			
		||||
    );
 | 
			
		||||
    // 监听组件update
 | 
			
		||||
    codeBlockService.addCodeRelationListener();
 | 
			
		||||
 | 
			
		||||
    return services;
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
@ -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>
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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 {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user