feat(stage): 1) 高亮边框样式加粗

2) 统一组件是否可选中逻辑,固定定位和绝对定位不可混合多选
3) 多选moveable options接受业务传入的moveableOptions
This commit is contained in:
parisma 2022-07-25 15:40:26 +08:00 committed by jia000
parent a4884c504f
commit a2fb92d988
5 changed files with 85 additions and 32 deletions

View File

@ -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节点

View File

@ -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,
});
}

View File

@ -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 => {

View File

@ -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,
};
}
}

View File

@ -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}`;