From c949590f805b6778f4f02e873f58bde1011cbefe Mon Sep 17 00:00:00 2001 From: roymondchen Date: Fri, 12 Aug 2022 13:38:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(editor,stage):=20=E5=A4=9A=E9=80=89?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=B1=85=E4=B8=AD=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../editor/src/layouts/workspace/Stage.vue | 7 +- .../src/layouts/workspace/ViewerMenu.vue | 6 +- packages/editor/src/services/editor.ts | 65 ++++++++++++------- packages/stage/src/StageDragResize.ts | 8 ++- packages/stage/src/StageMultiDragResize.ts | 23 ++++--- packages/stage/src/types.ts | 26 ++++---- 6 files changed, 84 insertions(+), 51 deletions(-) diff --git a/packages/editor/src/layouts/workspace/Stage.vue b/packages/editor/src/layouts/workspace/Stage.vue index e0341166..3ba67bed 100644 --- a/packages/editor/src/layouts/workspace/Stage.vue +++ b/packages/editor/src/layouts/workspace/Stage.vue @@ -118,10 +118,13 @@ watchEffect(() => { stage?.on('update', (ev: UpdateEventData) => { if (ev.parentEl) { - services?.editorService.moveToContainer({ id: ev.el.id, style: ev.style }, ev.parentEl.id); + for (const data of ev.data) { + services?.editorService.moveToContainer({ id: data.el.id, style: data.style }, ev.parentEl.id); + } return; } - services?.editorService.update({ id: ev.el.id, style: ev.style }); + + services?.editorService.update(ev.data.map((data) => ({ id: data.el.id, style: data.style }))); }); stage?.on('sort', (ev: SortEventData) => { diff --git a/packages/editor/src/layouts/workspace/ViewerMenu.vue b/packages/editor/src/layouts/workspace/ViewerMenu.vue index 512f6253..00350eec 100644 --- a/packages/editor/src/layouts/workspace/ViewerMenu.vue +++ b/packages/editor/src/layouts/workspace/ViewerMenu.vue @@ -34,10 +34,10 @@ const menuData = reactive([ { type: 'button', text: '水平居中', - display: () => canCenter.value && !props.isMultiSelect, + display: () => canCenter.value, handler: () => { - if (!node.value) return; - editorService?.alignCenter(node.value); + if (!nodes.value) return; + editorService?.alignCenter(nodes.value); }, }, { diff --git a/packages/editor/src/services/editor.ts b/packages/editor/src/services/editor.ts index 7d1451eb..422fb573 100644 --- a/packages/editor/src/services/editor.ts +++ b/packages/editor/src/services/editor.ts @@ -64,11 +64,14 @@ class Editor extends BaseService { 'select', 'doAdd', 'add', + 'doRemove', 'remove', + 'doUpdate', 'update', 'sort', 'copy', 'paste', + 'duAlignCenter', 'alignCenter', 'moveLayer', 'moveToContainer', @@ -417,12 +420,7 @@ class Editor extends BaseService { this.emit('remove'); } - /** - * 更新节点 - * @param config 新的节点配置,配置中需要有id信息 - * @returns 更新后的节点配置 - */ - public async update(config: MNode): Promise { + public async doUpdate(config: MNode) { if (!config?.id) throw new Error('没有配置或者配置缺少id值'); const info = this.getNodeInfo(config.id, false); @@ -475,13 +473,27 @@ class Editor extends BaseService { } this.addModifiedNodeId(newConfig.id); - this.pushHistoryState(); - - this.emit('update', newConfig); return newConfig; } + /** + * 更新节点 + * @param config 新的节点配置,配置中需要有id信息 + * @returns 更新后的节点配置 + */ + public async update(config: MNode | MNode[]): Promise { + const nodes = Array.isArray(config) ? config : [config]; + + const newNodes = await Promise.all(nodes.map((node) => this.doUpdate(node))); + + this.pushHistoryState(); + + this.emit('update', newNodes); + + return newNodes.length > 1 ? newNodes[0] : newNodes; + } + /** * 将id为id1的组件移动到id为id2的组件位置上,例如:[1,2,3,4] -> sort(1,3) -> [2,1,3,4] * @param id1 组件ID @@ -533,15 +545,13 @@ class Editor extends BaseService { return this.add(pasteConfigs); } - /** - * 将指点节点设置居中 - * @param config 组件节点配置 - * @returns 当前组件节点配置 - */ - public async alignCenter(config: MNode): Promise { - const parent = this.get('parent'); + public async doAlignCenter(config: MNode): Promise { + const parent = this.getParentById(config.id); + + if (!parent) throw new Error('找不到父节点'); + const node = cloneDeep(toRaw(config)); - const layout = await this.getLayout(toRaw(parent), node); + const layout = await this.getLayout(parent, node); if (layout === Layout.RELATIVE) { return config; } @@ -561,12 +571,23 @@ class Editor extends BaseService { node.style.left = (parent.style.width - node.style.width) / 2; } - const newNode = await this.update(node); + return node; + } - this.get('stage')?.update({ - config: cloneDeep(toRaw(newNode)), - root: cloneDeep(this.get('root')), - }); + /** + * 将指点节点设置居中 + * @param config 组件节点配置 + * @returns 当前组件节点配置 + */ + public async alignCenter(config: MNode | MNode[]): Promise { + const nodes = Array.isArray(config) ? config : [config]; + const stage = this.get('stage'); + + const newNodes = await Promise.all(nodes.map((node) => this.doAlignCenter(node))); + + const newNode = await this.update(newNodes); + + await stage?.multiSelect(newNodes.map((node) => node.id)); return newNode; } diff --git a/packages/stage/src/StageDragResize.ts b/packages/stage/src/StageDragResize.ts index 7f8c3e9b..46c3f35e 100644 --- a/packages/stage/src/StageDragResize.ts +++ b/packages/stage/src/StageDragResize.ts @@ -450,9 +450,13 @@ export default class StageDragResize extends EventEmitter { } this.emit('update', { - el: this.target, + data: [ + { + el: this.target, + style: isResize ? { left, top, width, height } : { left, top }, + }, + ], parentEl, - style: isResize ? { left, top, width, height } : { left, top }, }); } diff --git a/packages/stage/src/StageMultiDragResize.ts b/packages/stage/src/StageMultiDragResize.ts index a7fd57e5..000772c7 100644 --- a/packages/stage/src/StageMultiDragResize.ts +++ b/packages/stage/src/StageMultiDragResize.ts @@ -205,16 +205,19 @@ export default class StageMultiDragResize extends EventEmitter { const doc = contentWindow?.document; if (!doc) return; - this.targetList.forEach((targetItem) => { - const offset = { left: targetItem.offsetLeft, top: targetItem.offsetTop }; - const left = calcValueByFontsize(doc, offset.left); - const top = calcValueByFontsize(doc, offset.top); - const width = calcValueByFontsize(doc, targetItem.clientWidth); - const height = calcValueByFontsize(doc, targetItem.clientHeight); - this.emit('update', { - el: targetItem, - style: isResize ? { left, top, width, height } : { left, top }, - }); + this.emit('update', { + data: this.targetList.map((targetItem) => { + const offset = { left: targetItem.offsetLeft, top: targetItem.offsetTop }; + const left = calcValueByFontsize(doc, offset.left); + const top = calcValueByFontsize(doc, offset.top); + const width = calcValueByFontsize(doc, targetItem.clientWidth); + const height = calcValueByFontsize(doc, targetItem.clientHeight); + return { + el: targetItem, + style: isResize ? { left, top, width, height } : { left, top }, + }; + }), + parentEl: null, }); } diff --git a/packages/stage/src/types.ts b/packages/stage/src/types.ts index 0399082c..aaecb65d 100644 --- a/packages/stage/src/types.ts +++ b/packages/stage/src/types.ts @@ -87,19 +87,21 @@ export interface GuidesEventData { } export interface UpdateEventData { - el: HTMLElement; - parentEl: HTMLElement | null; - ghostEl: HTMLElement; - style: { - width?: number; - height?: number; - left?: number; - top?: number; - transform?: { - rotate?: string; - scale?: string; + data: { + el: HTMLElement; + style: { + width?: number; + height?: number; + left?: number; + top?: number; + transform?: { + rotate?: string; + scale?: string; + }; }; - }; + ghostEl?: HTMLElement; + }[]; + parentEl: HTMLElement | null; } export interface SortEventData {