mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-04-06 03:57:56 +08:00
支持通过按住shift键进行组件多选的能力 (#193)
* feat(stage): 支持绝对定位,固定定位,组内元素按住shift键进行多选拖拽能力 * refactor: 更新pnpm-lock.yaml * feat(stage): 使用moveable.helper接管moveable target的更新,针对弹窗场景引入业务方方法进行校准 * feat(stage): 将多选逻辑封装到StageMultiDragResize * fix(stage): cr意见修改 Co-authored-by: parisma <parisma@tencent.com>
This commit is contained in:
parent
1750467d5b
commit
fe520bf600
@ -40,7 +40,6 @@ import {
|
||||
isFixed,
|
||||
setLayout,
|
||||
} from '@editor/utils/editor';
|
||||
import { log } from '@editor/utils/logger';
|
||||
|
||||
import BaseService from './BaseService';
|
||||
|
||||
@ -90,7 +89,6 @@ class Editor extends BaseService {
|
||||
*/
|
||||
public set<T = MNode>(name: keyof StoreState, value: T) {
|
||||
this.state[name] = value as any;
|
||||
log('store set ', name, ' ', value);
|
||||
|
||||
if (name === 'root') {
|
||||
this.state.pageLength = (value as unknown as MApp)?.items?.length || 0;
|
||||
|
@ -31,6 +31,7 @@
|
||||
"@tmagic/schema": "1.1.0-beta.2",
|
||||
"@tmagic/utils": "1.1.0-beta.2",
|
||||
"events": "^3.3.0",
|
||||
"keycon": "^1.1.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moveable": "^0.30.0",
|
||||
"moveable-helper": "^0.4.0"
|
||||
|
@ -20,10 +20,11 @@ import { EventEmitter } from 'events';
|
||||
|
||||
import type { Id } from '@tmagic/schema';
|
||||
|
||||
import { DEFAULT_ZOOM, GHOST_EL_ID_PREFIX } from './const';
|
||||
import { DEFAULT_ZOOM, GHOST_EL_ID_PREFIX, PAGE_CLASS } from './const';
|
||||
import StageDragResize from './StageDragResize';
|
||||
import StageHighlight from './StageHighlight';
|
||||
import StageMask from './StageMask';
|
||||
import StageMultiDragResize from './StageMultiDragResize';
|
||||
import StageRender from './StageRender';
|
||||
import {
|
||||
CanSelect,
|
||||
@ -40,12 +41,15 @@ import { addSelectedClassName, removeSelectedClassName } from './util';
|
||||
|
||||
export default class StageCore extends EventEmitter {
|
||||
public container?: HTMLDivElement;
|
||||
|
||||
public selectedDom: Element | undefined;
|
||||
// 当前选中的节点
|
||||
public selectedDom: HTMLElement | undefined;
|
||||
// 多选选中的节点组
|
||||
public selectedDomList: HTMLElement[] = [];
|
||||
public highlightedDom: Element | undefined;
|
||||
public renderer: StageRender;
|
||||
public mask: StageMask;
|
||||
public dr: StageDragResize;
|
||||
public multiDr: StageMultiDragResize;
|
||||
public highlightLayer: StageHighlight;
|
||||
public config: StageCoreConfig;
|
||||
public zoom = DEFAULT_ZOOM;
|
||||
@ -68,7 +72,8 @@ export default class StageCore extends EventEmitter {
|
||||
|
||||
this.renderer = new StageRender({ core: this });
|
||||
this.mask = new StageMask({ core: this });
|
||||
this.dr = new StageDragResize({ core: this, container: this.mask.content });
|
||||
this.dr = new StageDragResize({ core: this, container: this.mask.content, mask: this.mask });
|
||||
this.multiDr = new StageMultiDragResize({ core: this, container: this.mask.content, mask: this.mask });
|
||||
this.highlightLayer = new StageHighlight({ core: this, container: this.mask.wrapper });
|
||||
|
||||
this.renderer.on('runtime-ready', (runtime: Runtime) => {
|
||||
@ -79,8 +84,11 @@ export default class StageCore extends EventEmitter {
|
||||
});
|
||||
|
||||
this.mask
|
||||
.on('beforeSelect', (event: MouseEvent) => {
|
||||
this.setElementFromPoint(event);
|
||||
.on('beforeSelect', async (event: MouseEvent) => {
|
||||
this.clearSelectStatus('multiSelect');
|
||||
const el = await this.setElementFromPoint(event);
|
||||
if (!el) return;
|
||||
this.select(el, event);
|
||||
})
|
||||
.on('select', () => {
|
||||
this.emit('select', this.selectedDom);
|
||||
@ -90,16 +98,39 @@ export default class StageCore extends EventEmitter {
|
||||
this.emit('changeGuides', data);
|
||||
})
|
||||
.on('highlight', async (event: MouseEvent) => {
|
||||
await this.setElementFromPoint(event);
|
||||
const el = await this.setElementFromPoint(event, 'mousemove');
|
||||
if (!el) return;
|
||||
await this.highlight(el);
|
||||
if (this.highlightedDom === this.selectedDom) {
|
||||
this.highlightLayer.clearHighlight();
|
||||
return;
|
||||
}
|
||||
this.highlightLayer.highlight(this.highlightedDom as HTMLElement);
|
||||
this.emit('highlight', this.highlightedDom);
|
||||
})
|
||||
.on('clearHighlight', async () => {
|
||||
this.highlightLayer.clearHighlight();
|
||||
})
|
||||
.on('beforeMultiSelect', async (event: MouseEvent) => {
|
||||
const el = await this.setElementFromPoint(event);
|
||||
if (!el) return;
|
||||
// 多选不可以选中magic-ui-page
|
||||
if (el.className.includes(PAGE_CLASS)) return;
|
||||
this.clearSelectStatus('select');
|
||||
// 如果已有单选选中元素,不是magic-ui-page就可以加入多选列表
|
||||
if (this.selectedDom && !this.selectedDom.className.includes(PAGE_CLASS)) {
|
||||
this.selectedDomList.push(this.selectedDom as HTMLElement);
|
||||
this.selectedDom = undefined;
|
||||
}
|
||||
// 判断元素是否已在多选列表
|
||||
const existIndex = this.selectedDomList.findIndex((selectedDom) => selectedDom.id === el.id);
|
||||
if (existIndex !== -1) {
|
||||
// 再次点击取消选中
|
||||
this.selectedDomList.splice(existIndex, 1);
|
||||
} else {
|
||||
this.selectedDomList.push(el);
|
||||
}
|
||||
this.multiDr.multiSelect(this.selectedDomList);
|
||||
this.emit('multiSelect', this.selectedDomList);
|
||||
});
|
||||
|
||||
// 要先触发select,在触发update
|
||||
@ -130,20 +161,17 @@ export default class StageCore extends EventEmitter {
|
||||
return doc?.elementsFromPoint(x / zoom, y / zoom) as HTMLElement[];
|
||||
}
|
||||
|
||||
public async setElementFromPoint(event: MouseEvent) {
|
||||
public async setElementFromPoint(event: MouseEvent, type?: String) {
|
||||
const els = this.getElementsFromPoint(event);
|
||||
|
||||
let stopped = false;
|
||||
const stop = () => (stopped = true);
|
||||
for (const el of els) {
|
||||
if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.canSelect(el, event, stop))) {
|
||||
if (stopped) break;
|
||||
if (event.type === 'mousemove') {
|
||||
this.highlight(el);
|
||||
break;
|
||||
if (event.type === type) {
|
||||
return el;
|
||||
}
|
||||
this.select(el, event);
|
||||
break;
|
||||
return el;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -166,6 +194,7 @@ export default class StageCore extends EventEmitter {
|
||||
}
|
||||
|
||||
this.mask.setLayout(el);
|
||||
this.multiDr.destroyDragElList();
|
||||
this.dr.select(el, event);
|
||||
|
||||
if (this.config.autoScrollIntoView || el.dataset.autoScrollIntoView) {
|
||||
@ -217,7 +246,7 @@ export default class StageCore extends EventEmitter {
|
||||
this.highlightLayer.clearHighlight();
|
||||
return;
|
||||
}
|
||||
if (el === this.highlightedDom) return;
|
||||
if (el === this.highlightedDom || !el) return;
|
||||
this.highlightLayer.highlight(el);
|
||||
this.highlightedDom = el;
|
||||
}
|
||||
@ -238,6 +267,19 @@ export default class StageCore extends EventEmitter {
|
||||
this.zoom = zoom;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于在切换选择模式时清除上一次的状态
|
||||
* @param selectType 需要清理的选择模式 多选:multiSelect,单选:select
|
||||
*/
|
||||
public clearSelectStatus(selectType: String) {
|
||||
if (selectType === 'multiSelect') {
|
||||
this.multiDr.clearSelectStatus();
|
||||
this.selectedDomList = [];
|
||||
} else {
|
||||
this.dr.clearSelectStatus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂载Dom节点
|
||||
* @param el 将stage挂载到该Dom节点上
|
||||
|
@ -27,8 +27,9 @@ import { addClassName, removeClassNameByClassName } from '@tmagic/utils';
|
||||
|
||||
import { DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, Mode, ZIndex } from './const';
|
||||
import StageCore from './StageCore';
|
||||
import StageMask from './StageMask';
|
||||
import type { SortEventData, StageDragResizeConfig } from './types';
|
||||
import { calcValueByFontsize, getAbsolutePosition, getMode, getOffset } from './util';
|
||||
import { calcValueByFontsize, getAbsolutePosition, getMode, getOffset, getTargetElStyle } from './util';
|
||||
|
||||
/** 拖动状态 */
|
||||
enum ActionStatus {
|
||||
@ -45,14 +46,21 @@ enum ActionStatus {
|
||||
*/
|
||||
export default class StageDragResize extends EventEmitter {
|
||||
public core: StageCore;
|
||||
public mask: StageMask;
|
||||
/** 画布容器 */
|
||||
public container: HTMLElement;
|
||||
/** 目标节点 */
|
||||
public target?: HTMLElement;
|
||||
/** 目标节点在蒙层中的占位节点 */
|
||||
public dragEl: HTMLDivElement;
|
||||
public dragEl?: HTMLDivElement;
|
||||
/** 多选:目标节点组 */
|
||||
public targetList: HTMLElement[] = [];
|
||||
/** 多选:目标节点在蒙层中的占位节点组 */
|
||||
public dragElList: HTMLDivElement[] = [];
|
||||
/** Moveable拖拽类实例 */
|
||||
public moveable?: Moveable;
|
||||
/** Moveable多选拖拽类实例 */
|
||||
public moveableForMulti?: Moveable;
|
||||
/** 水平参考线 */
|
||||
public horizontalGuidelines: number[] = [];
|
||||
/** 垂直参考线 */
|
||||
@ -74,9 +82,7 @@ export default class StageDragResize extends EventEmitter {
|
||||
|
||||
this.core = config.core;
|
||||
this.container = config.container;
|
||||
|
||||
this.dragEl = globalThis.document.createElement('div');
|
||||
this.container.append(this.dragEl);
|
||||
this.mask = config.mask;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,6 +153,17 @@ export default class StageDragResize extends EventEmitter {
|
||||
this.updateMoveable();
|
||||
}
|
||||
|
||||
public clearSelectStatus(): void {
|
||||
if (!this.moveable) return;
|
||||
this.destroyDragEl();
|
||||
this.moveable.target = null;
|
||||
this.moveable.updateTarget();
|
||||
}
|
||||
|
||||
public destroyDragEl(): void {
|
||||
this.dragEl?.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁实例
|
||||
*/
|
||||
@ -166,9 +183,15 @@ export default class StageDragResize extends EventEmitter {
|
||||
this.mode = getMode(el);
|
||||
|
||||
this.destroyGhostEl();
|
||||
this.destroyDragEl();
|
||||
this.dragEl = globalThis.document.createElement('div');
|
||||
this.container.append(this.dragEl);
|
||||
this.dragEl.style.cssText = getTargetElStyle(el);
|
||||
this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
|
||||
|
||||
this.updateDragEl(el);
|
||||
|
||||
if (typeof this.core.config.updateDragEl === 'function') {
|
||||
this.core.config.updateDragEl(this.dragEl, el);
|
||||
}
|
||||
this.moveableOptions = this.getOptions({
|
||||
target: this.dragEl,
|
||||
});
|
||||
@ -282,7 +305,6 @@ export default class StageDragResize extends EventEmitter {
|
||||
if (this.mode === Mode.SORTABLE) {
|
||||
this.ghostEl = this.generateGhostEl(this.target);
|
||||
}
|
||||
|
||||
frame.top = this.target.offsetTop;
|
||||
frame.left = this.target.offsetLeft;
|
||||
})
|
||||
@ -483,31 +505,6 @@ export default class StageDragResize extends EventEmitter {
|
||||
this.ghostEl = undefined;
|
||||
}
|
||||
|
||||
private updateDragEl(el: HTMLElement) {
|
||||
const offset = getOffset(el);
|
||||
const { transform } = getComputedStyle(el);
|
||||
|
||||
this.dragEl.style.cssText = `
|
||||
position: absolute;
|
||||
transform: ${transform};
|
||||
left: ${offset.left}px;
|
||||
top: ${offset.top}px;
|
||||
width: ${el.clientWidth}px;
|
||||
height: ${el.clientHeight}px;
|
||||
z-index: ${ZIndex.DRAG_EL};
|
||||
`;
|
||||
|
||||
this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
|
||||
|
||||
if (typeof this.core.config.updateDragEl === 'function') {
|
||||
this.core.config.updateDragEl(this.dragEl, el);
|
||||
}
|
||||
}
|
||||
|
||||
private destroyDragEl(): void {
|
||||
this.dragEl?.remove();
|
||||
}
|
||||
|
||||
private getOptions(options: MoveableOptions = {}): MoveableOptions {
|
||||
if (!this.target) return {};
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import KeyController from 'keycon';
|
||||
import { throttle } from 'lodash-es';
|
||||
|
||||
import { createDiv, injectStyle } from '@tmagic/utils';
|
||||
@ -82,6 +83,7 @@ export default class StageMask extends Rule {
|
||||
public maxScrollTop = 0;
|
||||
public maxScrollLeft = 0;
|
||||
public intersectionObserver: IntersectionObserver | null = null;
|
||||
public shiftKeyDown: Boolean = false;
|
||||
|
||||
private mode: Mode = Mode.ABSOLUTE;
|
||||
private pageResizeObserver: ResizeObserver | null = null;
|
||||
@ -106,6 +108,14 @@ export default class StageMask extends Rule {
|
||||
this.content.addEventListener('wheel', this.mouseWheelHandler);
|
||||
this.content.addEventListener('mousemove', this.highlightHandler);
|
||||
this.content.addEventListener('mouseleave', this.mouseLeaveHandler);
|
||||
KeyController.global.keydown('shift', (e) => {
|
||||
e.inputEvent.preventDefault();
|
||||
this.shiftKeyDown = true;
|
||||
});
|
||||
KeyController.global.keyup('shift', (e) => {
|
||||
e.inputEvent.preventDefault();
|
||||
this.shiftKeyDown = false;
|
||||
});
|
||||
}
|
||||
|
||||
public setMode(mode: Mode) {
|
||||
@ -292,23 +302,30 @@ export default class StageMask extends Rule {
|
||||
*/
|
||||
private mouseDownHandler = (event: MouseEvent): void => {
|
||||
this.emit('clearHighlight');
|
||||
|
||||
event.stopImmediatePropagation();
|
||||
event.stopPropagation();
|
||||
|
||||
if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT) return;
|
||||
|
||||
// 点击的对象如果是选中框,则不需要再触发选中了,而可能是拖动行为
|
||||
// 如果单击多选选中区域,则不需要再触发选中了,而可能是拖动行为
|
||||
if (!this.shiftKeyDown && (event.target as HTMLDivElement).className.indexOf('moveable-area') !== -1) {
|
||||
return;
|
||||
}
|
||||
// 点击对象如果是边框锚点,则可能是resize
|
||||
if ((event.target as HTMLDivElement).className.indexOf('moveable-control') !== -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.content.removeEventListener('mousemove', this.highlightHandler);
|
||||
|
||||
this.emit('beforeSelect', event);
|
||||
|
||||
// 如果是右键点击,这里的mouseup事件监听没有效果
|
||||
globalThis.document.addEventListener('mouseup', this.mouseUpHandler);
|
||||
// 判断触发多选还是单选
|
||||
if (this.shiftKeyDown) {
|
||||
this.emit('beforeMultiSelect', event);
|
||||
} else {
|
||||
this.emit('beforeSelect', event);
|
||||
// 如果是右键点击,这里的mouseup事件监听没有效果
|
||||
globalThis.document.addEventListener('mouseup', this.mouseUpHandler);
|
||||
}
|
||||
};
|
||||
|
||||
private mouseUpHandler = (): void => {
|
||||
|
156
packages/stage/src/StageMultiDragResize.ts
Normal file
156
packages/stage/src/StageMultiDragResize.ts
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
||||
*
|
||||
* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
import Moveable from 'moveable';
|
||||
import MoveableHelper from 'moveable-helper';
|
||||
|
||||
import { DRAG_EL_ID_PREFIX } from './const';
|
||||
import StageCore from './StageCore';
|
||||
import StageMask from './StageMask';
|
||||
import { StageDragResizeConfig } from './types';
|
||||
import { getTargetElStyle } from './util';
|
||||
export default class StageMultiDragResize extends EventEmitter {
|
||||
public core: StageCore;
|
||||
public mask: StageMask;
|
||||
/** 画布容器 */
|
||||
public container: HTMLElement;
|
||||
/** 多选:目标节点组 */
|
||||
public targetList: HTMLElement[] = [];
|
||||
/** 多选:目标节点在蒙层中的占位节点组 */
|
||||
public dragElList: HTMLDivElement[] = [];
|
||||
/** Moveable多选拖拽类实例 */
|
||||
public moveableForMulti?: Moveable;
|
||||
private multiMoveableHelper?: MoveableHelper;
|
||||
|
||||
constructor(config: StageDragResizeConfig) {
|
||||
super();
|
||||
|
||||
this.core = config.core;
|
||||
this.container = config.container;
|
||||
this.mask = config.mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多选
|
||||
* @param els
|
||||
*/
|
||||
public multiSelect(els: HTMLElement[]): void {
|
||||
this.targetList = els;
|
||||
this.core.dr.destroyDragEl();
|
||||
this.destroyDragElList();
|
||||
// 生成虚拟多选节点
|
||||
this.dragElList = els.map((elItem) => {
|
||||
const dragElDiv = globalThis.document.createElement('div');
|
||||
this.container.append(dragElDiv);
|
||||
dragElDiv.style.cssText = getTargetElStyle(elItem);
|
||||
dragElDiv.id = `${DRAG_EL_ID_PREFIX}${elItem.id}`;
|
||||
// 业务方校准
|
||||
if (typeof this.core.config.updateDragEl === 'function') {
|
||||
this.core.config.updateDragEl(dragElDiv, elItem);
|
||||
}
|
||||
return dragElDiv;
|
||||
});
|
||||
this.moveableForMulti?.destroy();
|
||||
this.multiMoveableHelper?.clear();
|
||||
|
||||
this.moveableForMulti = new Moveable(this.container, {
|
||||
target: this.dragElList,
|
||||
defaultGroupRotate: 0,
|
||||
defaultGroupOrigin: '50% 50%',
|
||||
draggable: true,
|
||||
resizable: true,
|
||||
throttleDrag: 0,
|
||||
startDragRotate: 0,
|
||||
throttleDragRotate: 0,
|
||||
zoom: 1,
|
||||
origin: true,
|
||||
padding: { left: 0, top: 0, right: 0, bottom: 0 },
|
||||
});
|
||||
this.multiMoveableHelper = MoveableHelper.create({
|
||||
useBeforeRender: true,
|
||||
useRender: false,
|
||||
createAuto: true,
|
||||
});
|
||||
const frames: { left: number; top: number; dragLeft: number; dragTop: number; id: string }[] = [];
|
||||
this.moveableForMulti
|
||||
.on('dragGroupStart', (params) => {
|
||||
const { events } = params;
|
||||
this.multiMoveableHelper?.onDragGroupStart(params);
|
||||
// 记录拖动前快照
|
||||
events.forEach((ev) => {
|
||||
// 实际目标元素
|
||||
const matchEventTarget = this.targetList.find((targetItem) => targetItem.id === ev.target.id.split('_')[2]);
|
||||
// 蒙层虚拟元素(对于在组内的元素拖动时的相对位置不同,因此需要分别记录)
|
||||
const dragEventTarget = ev.target as HTMLDivElement;
|
||||
if (!matchEventTarget || !dragEventTarget) return;
|
||||
frames.push({
|
||||
left: matchEventTarget.offsetLeft,
|
||||
top: matchEventTarget.offsetTop,
|
||||
dragLeft: dragEventTarget.offsetLeft,
|
||||
dragTop: dragEventTarget.offsetTop,
|
||||
id: matchEventTarget.id,
|
||||
});
|
||||
});
|
||||
})
|
||||
.on('dragGroup', (params) => {
|
||||
const { events } = params;
|
||||
// 拖动过程更新
|
||||
events.forEach((ev) => {
|
||||
const frameSnapShot = frames.find((frameItem) => frameItem.id === ev.target.id.split('_')[2]);
|
||||
if (!frameSnapShot) return;
|
||||
const targeEl = this.targetList.find((targetItem) => targetItem.id === ev.target.id.split('_')[2]);
|
||||
if (!targeEl) return;
|
||||
// 元素与其所属组同时加入多选列表时,只更新父元素
|
||||
const isParentIncluded = this.targetList.find((targetItem) => targetItem.id === targeEl.parentElement?.id);
|
||||
if (!isParentIncluded) {
|
||||
// 更新页面元素位置
|
||||
targeEl.style.left = `${frameSnapShot.left + ev.beforeTranslate[0]}px`;
|
||||
targeEl.style.top = `${frameSnapShot.top + ev.beforeTranslate[1]}px`;
|
||||
}
|
||||
});
|
||||
this.multiMoveableHelper?.onDragGroup(params);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除多选状态
|
||||
*/
|
||||
public clearSelectStatus(): void {
|
||||
if (!this.moveableForMulti) return;
|
||||
this.destroyDragElList();
|
||||
this.moveableForMulti.target = null;
|
||||
this.moveableForMulti.updateTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁实例
|
||||
*/
|
||||
public destroy(): void {
|
||||
this.moveableForMulti?.destroy();
|
||||
this.destroyDragElList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除蒙层占位节点
|
||||
*/
|
||||
public destroyDragElList(): void {
|
||||
this.dragElList.forEach((dragElItem) => dragElItem?.remove());
|
||||
}
|
||||
}
|
@ -27,6 +27,8 @@ export const HIGHLIGHT_EL_ID_PREFIX = 'highlight_el_';
|
||||
|
||||
export const CONTAINER_HIGHLIGHT_CLASS = 'tmagic-stage-container-highlight';
|
||||
|
||||
export const PAGE_CLASS = 'magic-ui-page';
|
||||
|
||||
/** 默认放到缩小倍数 */
|
||||
export const DEFAULT_ZOOM = 1;
|
||||
|
||||
|
@ -57,6 +57,7 @@ export interface StageMaskConfig {
|
||||
export interface StageDragResizeConfig {
|
||||
core: StageCore;
|
||||
container: HTMLElement;
|
||||
mask: StageMask;
|
||||
}
|
||||
|
||||
export type Rect = {
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
import { removeClassName } from '@tmagic/utils';
|
||||
|
||||
import { Mode, SELECTED_CLASS } from './const';
|
||||
import { Mode, SELECTED_CLASS, ZIndex } from './const';
|
||||
import type { Offset } from './types';
|
||||
|
||||
const getParents = (el: Element, relative: Element) => {
|
||||
@ -50,6 +50,21 @@ export const getOffset = (el: HTMLElement): Offset => {
|
||||
};
|
||||
};
|
||||
|
||||
// 将蒙层占位节点覆盖在原节点上方
|
||||
export const getTargetElStyle = (el: HTMLElement) => {
|
||||
const offset = getOffset(el);
|
||||
const { transform } = getComputedStyle(el);
|
||||
return `
|
||||
position: absolute;
|
||||
transform: ${transform};
|
||||
left: ${offset.left}px;
|
||||
top: ${offset.top}px;
|
||||
width: ${el.clientWidth}px;
|
||||
height: ${el.clientHeight}px;
|
||||
z-index: ${ZIndex.DRAG_EL};
|
||||
`;
|
||||
};
|
||||
|
||||
export const getAbsolutePosition = (el: HTMLElement, { top, left }: Offset) => {
|
||||
const { offsetParent } = el;
|
||||
|
||||
|
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@ -254,6 +254,7 @@ importers:
|
||||
'@types/lodash-es': ^4.17.4
|
||||
'@types/node': ^15.12.4
|
||||
events: ^3.3.0
|
||||
keycon: ^1.1.2
|
||||
lodash-es: ^4.17.21
|
||||
moveable: ^0.30.0
|
||||
moveable-helper: ^0.4.0
|
||||
@ -267,6 +268,7 @@ importers:
|
||||
'@tmagic/schema': link:../schema
|
||||
'@tmagic/utils': link:../utils
|
||||
events: 3.3.0
|
||||
keycon: 1.1.2
|
||||
lodash-es: 4.17.21
|
||||
moveable: 0.30.0
|
||||
moveable-helper: 0.4.0
|
||||
@ -3075,7 +3077,7 @@ packages:
|
||||
lodash: ^4.17.20
|
||||
marko: ^3.14.4
|
||||
mote: ^0.2.0
|
||||
mustache: ^3.0.0
|
||||
mustache: ^4.0.1
|
||||
nunjucks: ^3.2.2
|
||||
plates: ~0.4.11
|
||||
pug: ^3.0.0
|
||||
@ -5519,7 +5521,7 @@ packages:
|
||||
/keycon/1.1.2:
|
||||
resolution: {integrity: sha512-yCoUAfwqmQUWrtOFuZhicxasF/4ae+M0aH8yV1wEKKZCZql8v6jWhlVF9dT5i1TfuHSmgt/GNuCaWIHT8wk6eQ==}
|
||||
dependencies:
|
||||
'@daybrush/utils': 1.6.0
|
||||
'@daybrush/utils': 1.7.1
|
||||
'@scena/event-emitter': 1.0.5
|
||||
keycode: 2.2.1
|
||||
dev: false
|
||||
|
Loading…
x
Reference in New Issue
Block a user