mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-04-06 03:57:56 +08:00
feat(stage): 1) 高亮边框样式加粗
2) 统一组件是否可选中逻辑,固定定位和绝对定位不可混合多选 3) 多选moveable options接受业务传入的moveableOptions
This commit is contained in:
parent
a4884c504f
commit
a2fb92d988
@ -99,7 +99,7 @@ export default class StageCore extends EventEmitter {
|
||||
this.emit('changeGuides', data);
|
||||
})
|
||||
.on('highlight', async (event: MouseEvent) => {
|
||||
const el = await this.getElementFromPoint(event, 'mousemove');
|
||||
const el = await this.getElementFromPoint(event);
|
||||
if (!el) return;
|
||||
await this.highlight(el);
|
||||
if (this.highlightedDom === this.selectedDom) {
|
||||
@ -114,8 +114,6 @@ export default class StageCore extends EventEmitter {
|
||||
.on('beforeMultiSelect', async (event: MouseEvent) => {
|
||||
const el = await this.getElementFromPoint(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)) {
|
||||
@ -166,21 +164,29 @@ export default class StageCore extends EventEmitter {
|
||||
return doc?.elementsFromPoint(x / zoom, y / zoom) as HTMLElement[];
|
||||
}
|
||||
|
||||
public async getElementFromPoint(event: MouseEvent, type?: String) {
|
||||
public async getElementFromPoint(event: MouseEvent) {
|
||||
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 (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.isElCanSelect(el, event, stop))) {
|
||||
if (stopped) break;
|
||||
if (event.type === type) {
|
||||
return el;
|
||||
}
|
||||
return el;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async isElCanSelect(el: HTMLElement, event: MouseEvent, stop: () => boolean): Promise<Boolean> {
|
||||
// 执行业务方传入的判断逻辑
|
||||
const canSelectByProp = await this.canSelect(el, event, stop);
|
||||
if (!canSelectByProp) return false;
|
||||
// 多选规则
|
||||
if (this.mask.isMultiSelectStatus) {
|
||||
return this.multiDr.canSelect(el);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 选中组件
|
||||
* @param idOrEl 组件Dom节点的id属性,或者Dom节点
|
||||
|
@ -57,7 +57,7 @@ export default class StageHighlight extends EventEmitter {
|
||||
target: this.calibrationTarget.update(el, HIGHLIGHT_EL_ID_PREFIX),
|
||||
origin: false,
|
||||
rootContainer: this.core.container,
|
||||
zoom: 1,
|
||||
zoom: 2,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ export default class StageMask extends Rule {
|
||||
public maxScrollTop = 0;
|
||||
public maxScrollLeft = 0;
|
||||
public intersectionObserver: IntersectionObserver | null = null;
|
||||
public shiftKeyDown: Boolean = false;
|
||||
public isMultiSelectStatus: Boolean = false;
|
||||
|
||||
private mode: Mode = Mode.ABSOLUTE;
|
||||
private pageResizeObserver: ResizeObserver | null = null;
|
||||
@ -110,11 +110,11 @@ export default class StageMask extends Rule {
|
||||
this.content.addEventListener('mouseleave', this.mouseLeaveHandler);
|
||||
KeyController.global.keydown('shift', (e) => {
|
||||
e.inputEvent.preventDefault();
|
||||
this.shiftKeyDown = true;
|
||||
this.isMultiSelectStatus = true;
|
||||
});
|
||||
KeyController.global.keyup('shift', (e) => {
|
||||
e.inputEvent.preventDefault();
|
||||
this.shiftKeyDown = false;
|
||||
this.isMultiSelectStatus = false;
|
||||
});
|
||||
}
|
||||
|
||||
@ -308,7 +308,7 @@ export default class StageMask extends Rule {
|
||||
if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT) return;
|
||||
|
||||
// 如果单击多选选中区域,则不需要再触发选中了,而可能是拖动行为
|
||||
if (!this.shiftKeyDown && (event.target as HTMLDivElement).className.indexOf('moveable-area') !== -1) {
|
||||
if (!this.isMultiSelectStatus && (event.target as HTMLDivElement).className.indexOf('moveable-area') !== -1) {
|
||||
return;
|
||||
}
|
||||
// 点击对象如果是边框锚点,则可能是resize
|
||||
@ -319,13 +319,13 @@ export default class StageMask extends Rule {
|
||||
this.content.removeEventListener('mousemove', this.highlightHandler);
|
||||
|
||||
// 判断触发多选还是单选
|
||||
if (this.shiftKeyDown) {
|
||||
if (this.isMultiSelectStatus) {
|
||||
this.emit('beforeMultiSelect', event);
|
||||
} else {
|
||||
this.emit('beforeSelect', event);
|
||||
// 如果是右键点击,这里的mouseup事件监听没有效果
|
||||
globalThis.document.addEventListener('mouseup', this.mouseUpHandler);
|
||||
}
|
||||
// 如果是右键点击,这里的mouseup事件监听没有效果
|
||||
globalThis.document.addEventListener('mouseup', this.mouseUpHandler);
|
||||
};
|
||||
|
||||
private mouseUpHandler = (): void => {
|
||||
|
@ -18,14 +18,15 @@
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
import type { MoveableOptions } from 'moveable';
|
||||
import Moveable from 'moveable';
|
||||
import MoveableHelper from 'moveable-helper';
|
||||
|
||||
import { DRAG_EL_ID_PREFIX } from './const';
|
||||
import { DRAG_EL_ID_PREFIX, PAGE_CLASS } from './const';
|
||||
import StageCore from './StageCore';
|
||||
import StageMask from './StageMask';
|
||||
import { StageDragResizeConfig } from './types';
|
||||
import { calcValueByFontsize, getTargetElStyle } from './util';
|
||||
import { calcValueByFontsize, getMode, getTargetElStyle } from './util';
|
||||
export default class StageMultiDragResize extends EventEmitter {
|
||||
public core: StageCore;
|
||||
public mask: StageMask;
|
||||
@ -70,19 +71,12 @@ export default class StageMultiDragResize extends EventEmitter {
|
||||
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.moveableForMulti = new Moveable(
|
||||
this.container,
|
||||
this.getOptions({
|
||||
target: this.dragElList,
|
||||
}),
|
||||
);
|
||||
this.multiMoveableHelper = MoveableHelper.create({
|
||||
useBeforeRender: true,
|
||||
useRender: false,
|
||||
@ -134,6 +128,30 @@ export default class StageMultiDragResize extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
public canSelect(el: HTMLElement): Boolean {
|
||||
// 多选不可以选中magic-ui-page
|
||||
if (el.className.includes(PAGE_CLASS)) {
|
||||
this.core.highlightedDom = undefined;
|
||||
this.core.highlightLayer.clearHighlight();
|
||||
return false;
|
||||
}
|
||||
const currentTargetMode = getMode(el);
|
||||
let selectedDomMode = '';
|
||||
|
||||
if (this.targetList.length === 0 && this.core.selectedDom) {
|
||||
// 单选后添加到多选的情况
|
||||
selectedDomMode = getMode(this.core.selectedDom);
|
||||
} else if (this.targetList.length > 0) {
|
||||
// 已加入多选列表的布局模式是一样的,取第一个判断
|
||||
selectedDomMode = getMode(this.targetList[0]);
|
||||
}
|
||||
// 定位模式不同,不可混选
|
||||
if (currentTargetMode !== selectedDomMode) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除多选状态
|
||||
*/
|
||||
@ -142,6 +160,7 @@ export default class StageMultiDragResize extends EventEmitter {
|
||||
this.destroyDragElList();
|
||||
this.moveableForMulti.target = null;
|
||||
this.moveableForMulti.updateTarget();
|
||||
this.targetList = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,4 +201,31 @@ export default class StageMultiDragResize extends EventEmitter {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取moveable options参数
|
||||
* @param {MoveableOptions} options
|
||||
* @return {MoveableOptions} moveable options参数
|
||||
*/
|
||||
private getOptions(options: MoveableOptions = {}): MoveableOptions {
|
||||
let { moveableOptions = {} } = this.core.config;
|
||||
|
||||
if (typeof moveableOptions === 'function') {
|
||||
moveableOptions = moveableOptions(this.core);
|
||||
}
|
||||
return {
|
||||
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 },
|
||||
...options,
|
||||
...moveableOptions,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
import { Mode } from './const';
|
||||
import { Mode, ZIndex } from './const';
|
||||
import StageCore from './StageCore';
|
||||
import StageDragResize from './StageDragResize';
|
||||
import StageMask from './StageMask';
|
||||
@ -57,6 +57,7 @@ export default class TargetCalibrate extends EventEmitter {
|
||||
top: ${top}px;
|
||||
width: ${el.clientWidth}px;
|
||||
height: ${el.clientHeight}px;
|
||||
z-index: ${ZIndex.DRAG_EL};
|
||||
`;
|
||||
|
||||
this.operationEl.id = `${prefix}${el.id}`;
|
||||
|
Loading…
x
Reference in New Issue
Block a user