From 3b6ca97f4ceeab215cb9d43b237159993bb6370b Mon Sep 17 00:00:00 2001 From: roymondchen Date: Mon, 27 Mar 2023 19:09:47 +0800 Subject: [PATCH] =?UTF-8?q?feat(edtior):=20=E4=BB=A3=E7=A0=81=E5=9D=97?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E4=BE=9D=E8=B5=96=E6=94=B6=E9=9B=86=E5=99=A8?= =?UTF-8?q?=E6=94=B9=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/editor/src/Editor.vue | 90 +++++++-- packages/editor/src/index.ts | 1 + .../sidebar/code-block/CodeBlockList.vue | 176 +++++------------- packages/editor/src/services/codeBlock.ts | 121 +----------- packages/editor/src/theme/code-block.scss | 38 +--- packages/editor/src/type.ts | 4 +- 6 files changed, 137 insertions(+), 293 deletions(-) diff --git a/packages/editor/src/Editor.vue b/packages/editor/src/Editor.vue index 81659aec..f7136b73 100644 --- a/packages/editor/src/Editor.vue +++ b/packages/editor/src/Editor.vue @@ -68,7 +68,7 @@ import { defineComponent, onUnmounted, PropType, provide, reactive, toRaw, watch import { EventOption } from '@tmagic/core'; import type { FormConfig } from '@tmagic/form'; -import type { MApp, MNode } from '@tmagic/schema'; +import { CodeBlockContent, Id, MApp, MNode, MPage } from '@tmagic/schema'; import StageCore, { CONTAINER_HIGHLIGHT_CLASS_NAME, ContainerHighlightType, @@ -84,12 +84,14 @@ import Sidebar from './layouts/sidebar/Sidebar.vue'; import Workspace from './layouts/workspace/Workspace.vue'; import codeBlockService from './services/codeBlock'; import componentListService from './services/componentList'; +import depService from './services/dep'; import editorService from './services/editor'; import eventsService from './services/events'; import historyService from './services/history'; import propsService from './services/props'; import storageService from './services/storage'; import uiService from './services/ui'; +import { createCodeBlockTarget } from './utils/dep'; import type { ComponentGroup, MenuBarData, MenuButton, MenuComponent, Services, SideBarData, StageRect } from './type'; export default defineComponent({ @@ -227,7 +229,7 @@ export default defineComponent({ emits: ['props-panel-mounted', 'update:modelValue'], setup(props, { emit }) { - const rootChangeHandler = (value: MApp, preValue?: MApp | null) => { + const rootChangeHandler = async (value: MApp, preValue?: MApp | null) => { const nodeId = editorService.get('node')?.id || props.defaultSelected; let node; if (nodeId) { @@ -235,9 +237,9 @@ export default defineComponent({ } if (node && node !== value) { - editorService.select(node.id); + await editorService.select(node.id); } else if (value?.items?.length) { - editorService.select(value.items[0]); + await editorService.select(value.items[0]); } else if (value?.id) { editorService.set('nodes', [value]); editorService.set('parent', null); @@ -251,9 +253,57 @@ export default defineComponent({ value.codeBlocks = value.codeBlocks || {}; codeBlockService.setCodeDsl(value.codeBlocks); + + depService.removeTargets('code-block'); + + Object.entries(value.codeBlocks).forEach(([id, code]) => { + depService.addTarget(createCodeBlockTarget(id, code)); + }); + + if (value && Array.isArray(value.items)) { + depService.collect(value.items, true); + } else { + depService.clear(); + } }; + const nodeAddHandler = (nodes: MNode[]) => { + depService.collect(nodes); + }; + + const nodeUpdateHandler = (nodes: MNode[]) => { + depService.collect(nodes); + }; + + const nodeRemoveHandler = (nodes: MNode[]) => { + depService.clear(nodes); + }; + + const historyChangeHandler = (page: MPage) => { + depService.collect([page], true); + }; + + editorService.on('history-change', historyChangeHandler); editorService.on('root-change', rootChangeHandler); + editorService.on('add', nodeAddHandler); + editorService.on('remove', nodeRemoveHandler); + editorService.on('update', nodeUpdateHandler); + + const codeBlockAddOrUpdateHandler = (id: Id, codeBlock: CodeBlockContent) => { + if (depService.hasTarget(id)) { + depService.getTarget(id)!.name = codeBlock.name; + return; + } + + depService.addTarget(createCodeBlockTarget(id, codeBlock)); + }; + + const codeBlockRemoveHandler = (id: Id) => { + depService.removeTarget(id); + }; + + codeBlockService.on('addOrUpdate', codeBlockAddOrUpdateHandler); + codeBlockService.on('remove', codeBlockRemoveHandler); // 初始值变化,重新设置节点信息 watch( @@ -325,17 +375,6 @@ export default defineComponent({ }, ); - onUnmounted(() => { - editorService.resetState(); - historyService.resetState(); - propsService.resetState(); - uiService.resetState(); - componentListService.resetState(); - codeBlockService.resetState(); - - editorService.off('root-change', rootChangeHandler); - }); - const services: Services = { componentListService, eventsService, @@ -345,6 +384,7 @@ export default defineComponent({ uiService, storageService, codeBlockService, + depService, }; provide('services', services); @@ -366,8 +406,24 @@ export default defineComponent({ disabledDragStart: props.disabledDragStart, }), ); - // 监听组件update - codeBlockService.addCodeRelationListener(); + + onUnmounted(() => { + editorService.resetState(); + historyService.resetState(); + propsService.resetState(); + uiService.resetState(); + componentListService.resetState(); + codeBlockService.resetState(); + + editorService.off('history-change', historyChangeHandler); + editorService.off('root-change', rootChangeHandler); + editorService.off('add', nodeAddHandler); + editorService.off('remove', nodeRemoveHandler); + editorService.off('update', nodeUpdateHandler); + + codeBlockService.off('addOrUpdate', codeBlockAddOrUpdateHandler); + codeBlockService.off('remove', codeBlockRemoveHandler); + }); return services; }, diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 9dbbcdbf..b5ec9a4e 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -40,6 +40,7 @@ export { default as storageService } from './services/storage'; export { default as eventsService } from './services/events'; export { default as uiService } from './services/ui'; export { default as codeBlockService } from './services/codeBlock'; +export { default as depService } from './services/dep'; export { default as ComponentListPanel } from './layouts/sidebar/ComponentListPanel.vue'; export { default as LayerPanel } from './layouts/sidebar/LayerPanel.vue'; export { default as CodeSelect } from './fields/CodeSelect.vue'; diff --git a/packages/editor/src/layouts/sidebar/code-block/CodeBlockList.vue b/packages/editor/src/layouts/sidebar/code-block/CodeBlockList.vue index 2fb43b9d..41d92b57 100644 --- a/packages/editor/src/layouts/sidebar/code-block/CodeBlockList.vue +++ b/packages/editor/src/layouts/sidebar/code-block/CodeBlockList.vue @@ -19,190 +19,118 @@ - + - + - diff --git a/packages/editor/src/services/codeBlock.ts b/packages/editor/src/services/codeBlock.ts index ed9d2cb5..2e02bbba 100644 --- a/packages/editor/src/services/codeBlock.ts +++ b/packages/editor/src/services/codeBlock.ts @@ -17,12 +17,11 @@ */ import { reactive } from 'vue'; -import { cloneDeep, forIn, isEmpty, keys, omit, pick, union } from 'lodash-es'; +import { keys, pick } from 'lodash-es'; -import { CodeBlockContent, CodeBlockDSL, HookType, Id, MNode, MPage } from '@tmagic/schema'; +import { CodeBlockContent, CodeBlockDSL, Id } from '@tmagic/schema'; -import editorService from '../services/editor'; -import type { CodeRelation, CodeState, HookData } from '../type'; +import type { CodeState } from '../type'; import { CODE_DRAFT_STORAGE_KEY } from '../type'; import { info } from '../utils/logger'; @@ -36,7 +35,6 @@ class CodeBlock extends BaseService { editable: true, combineIds: [], undeletableList: [], - relations: {}, }); constructor() { @@ -112,6 +110,8 @@ class CodeBlock extends BaseService { ...existContent, ...codeConfigProcessed, }; + + this.emit('addOrUpdate', id, codeDsl[id]); } /** @@ -213,56 +213,6 @@ class CodeBlock extends BaseService { return this.state.combineIds; } - /** - * 监听组件更新来更新代码块绑定关系 - * @returns {void} - */ - 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); - }); - }); - // 监听历史记录,历史快照为页面整体,需要深层遍历更新 - editorService.on('history-change', (page: MPage) => { - const relations: CodeRelation = {}; - this.getNodeRelation(page, relations, true); - this.state.relations = relations; - }); - } - - /** - * 更新全部绑定关系 - * @returns {void} - */ - public refreshAllRelations(): void { - const root = editorService.get('root'); - if (!root) return; - const relations: CodeRelation = {}; - this.getNodeRelation(root, relations, true); - this.state.relations = relations; - } - - /** - * 获取绑定关系 - * @returns {CodeRelation} - */ - public getCombineInfo(): CodeRelation { - return this.state.relations; - } - /** * 获取不可删除列表 * @returns {Id[]} @@ -312,6 +262,8 @@ class CodeBlock extends BaseService { codeIds.forEach((id) => { delete currentDsl[id]; + + this.emit('remove', id); }); } @@ -342,65 +294,6 @@ class CodeBlock extends BaseService { this.removeAllListeners(); this.removeAllPlugins(); } - - /** - * 递归遍历dsl中挂载了代码块的节点,并更新绑定关系数据 - * @param {MNode} node 节点信息 - * @param {CodeRelation} relation 关系数据 - * @param {boolean} deep 是否深层遍历 - * @returns void - */ - private getNodeRelation(node: MNode, relation: CodeRelation, deep = false): void { - forIn(node, (value, key) => { - if (value?.hookType === HookType.CODE && !isEmpty(value.hookData)) { - value.hookData.forEach((relationItem: HookData) => { - if (relationItem.codeId) { - relation[node.id] = union(relation[node.id], [relationItem.codeId]); - } - }); - // continue - return; - } - let isContinue = false; - try { - // 只遍历更新当前组件的关系,不再深层遍历容器包含的组件 - isContinue = key !== 'items' && typeof value === 'object' && JSON.stringify(value).includes('hookType'); - } catch (error) { - console.error(error); - } - if (isContinue) { - // 检查value内部是否有嵌套 - const unConfirmedValue = { - id: node.id, - ...value, - }; - 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) => { - newRelations = this.deleteNodeRelation(item, newRelations); - }); - } - return newRelations; - } } export type CodeBlockService = CodeBlock; diff --git a/packages/editor/src/theme/code-block.scss b/packages/editor/src/theme/code-block.scss index 64d10f94..ba3d049f 100644 --- a/packages/editor/src/theme/code-block.scss +++ b/packages/editor/src/theme/code-block.scss @@ -1,13 +1,6 @@ .m-editor-code-block-list { height: 100%; margin-top: 5px; - - .el-tree-node__content { - height: auto; - } - .el-tree-node__label { - width: 100%; - } .code-header-wrapper { display: flex; align-items: center; @@ -32,45 +25,24 @@ .list-container { width: 100%; overflow: hidden; - margin-left: -25px; .list-item { display: flex; - align-items: center; + width: 100%; + .right-tool { - width: fit-content !important; display: flex; - align-items: center; + width: fit-content !important; .edit-icon { margin: 0 5px; } } .code-name { - font-size: 14px; - overflow: hidden; white-space: nowrap; + overflow: hidden; text-overflow: ellipsis; - padding: 10px 15px; width: 0 !important; flex: 1; - } - } - .code-comp-map-wrapper { - display: flex; - align-items: center; - flex-wrap: wrap; - margin-left: 20px; - margin-bottom: 5px; - .arrow-left { - transform: rotate(-45deg); - width: 20px; - height: 20px; - } - .code-comp { - margin-left: 5px; - padding: 5px; - .comp-delete-icon { - margin-left: 3px; - } + line-height: 18px; } } } diff --git a/packages/editor/src/type.ts b/packages/editor/src/type.ts index 995df9dc..43a4e933 100644 --- a/packages/editor/src/type.ts +++ b/packages/editor/src/type.ts @@ -30,6 +30,7 @@ import type { import type { CodeBlockService } from './services/codeBlock'; import type { ComponentListService } from './services/componentList'; +import type { DepService } from './services/dep'; import type { EditorService } from './services/editor'; import type { EventsService } from './services/events'; import type { HistoryService } from './services/history'; @@ -54,6 +55,7 @@ export interface Services { componentListService: ComponentListService; uiService: UiService; codeBlockService: CodeBlockService; + depService: DepService; } export interface StageOptions { @@ -339,8 +341,6 @@ export type CodeState = { combineIds: string[]; /** 为业务逻辑预留的不可删除的代码块列表,由业务逻辑维护(如代码块上线后不可删除) */ undeletableList: Id[]; - /** 代码块和组件的绑定关系 */ - relations: CodeRelation; }; export type HookData = {