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);
|
this.emit('changeGuides', data);
|
||||||
})
|
})
|
||||||
.on('highlight', async (event: MouseEvent) => {
|
.on('highlight', async (event: MouseEvent) => {
|
||||||
const el = await this.getElementFromPoint(event, 'mousemove');
|
const el = await this.getElementFromPoint(event);
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
await this.highlight(el);
|
await this.highlight(el);
|
||||||
if (this.highlightedDom === this.selectedDom) {
|
if (this.highlightedDom === this.selectedDom) {
|
||||||
@ -114,8 +114,6 @@ export default class StageCore extends EventEmitter {
|
|||||||
.on('beforeMultiSelect', async (event: MouseEvent) => {
|
.on('beforeMultiSelect', async (event: MouseEvent) => {
|
||||||
const el = await this.getElementFromPoint(event);
|
const el = await this.getElementFromPoint(event);
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
// 多选不可以选中magic-ui-page
|
|
||||||
if (el.className.includes(PAGE_CLASS)) return;
|
|
||||||
this.clearSelectStatus('select');
|
this.clearSelectStatus('select');
|
||||||
// 如果已有单选选中元素,不是magic-ui-page就可以加入多选列表
|
// 如果已有单选选中元素,不是magic-ui-page就可以加入多选列表
|
||||||
if (this.selectedDom && !this.selectedDom.className.includes(PAGE_CLASS)) {
|
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[];
|
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);
|
const els = this.getElementsFromPoint(event);
|
||||||
let stopped = false;
|
let stopped = false;
|
||||||
const stop = () => (stopped = true);
|
const stop = () => (stopped = true);
|
||||||
for (const el of els) {
|
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 (stopped) break;
|
||||||
if (event.type === type) {
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
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节点
|
* @param idOrEl 组件Dom节点的id属性,或者Dom节点
|
||||||
|
@ -57,7 +57,7 @@ export default class StageHighlight extends EventEmitter {
|
|||||||
target: this.calibrationTarget.update(el, HIGHLIGHT_EL_ID_PREFIX),
|
target: this.calibrationTarget.update(el, HIGHLIGHT_EL_ID_PREFIX),
|
||||||
origin: false,
|
origin: false,
|
||||||
rootContainer: this.core.container,
|
rootContainer: this.core.container,
|
||||||
zoom: 1,
|
zoom: 2,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ export default class StageMask extends Rule {
|
|||||||
public maxScrollTop = 0;
|
public maxScrollTop = 0;
|
||||||
public maxScrollLeft = 0;
|
public maxScrollLeft = 0;
|
||||||
public intersectionObserver: IntersectionObserver | null = null;
|
public intersectionObserver: IntersectionObserver | null = null;
|
||||||
public shiftKeyDown: Boolean = false;
|
public isMultiSelectStatus: Boolean = false;
|
||||||
|
|
||||||
private mode: Mode = Mode.ABSOLUTE;
|
private mode: Mode = Mode.ABSOLUTE;
|
||||||
private pageResizeObserver: ResizeObserver | null = null;
|
private pageResizeObserver: ResizeObserver | null = null;
|
||||||
@ -110,11 +110,11 @@ export default class StageMask extends Rule {
|
|||||||
this.content.addEventListener('mouseleave', this.mouseLeaveHandler);
|
this.content.addEventListener('mouseleave', this.mouseLeaveHandler);
|
||||||
KeyController.global.keydown('shift', (e) => {
|
KeyController.global.keydown('shift', (e) => {
|
||||||
e.inputEvent.preventDefault();
|
e.inputEvent.preventDefault();
|
||||||
this.shiftKeyDown = true;
|
this.isMultiSelectStatus = true;
|
||||||
});
|
});
|
||||||
KeyController.global.keyup('shift', (e) => {
|
KeyController.global.keyup('shift', (e) => {
|
||||||
e.inputEvent.preventDefault();
|
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 (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;
|
return;
|
||||||
}
|
}
|
||||||
// 点击对象如果是边框锚点,则可能是resize
|
// 点击对象如果是边框锚点,则可能是resize
|
||||||
@ -319,13 +319,13 @@ export default class StageMask extends Rule {
|
|||||||
this.content.removeEventListener('mousemove', this.highlightHandler);
|
this.content.removeEventListener('mousemove', this.highlightHandler);
|
||||||
|
|
||||||
// 判断触发多选还是单选
|
// 判断触发多选还是单选
|
||||||
if (this.shiftKeyDown) {
|
if (this.isMultiSelectStatus) {
|
||||||
this.emit('beforeMultiSelect', event);
|
this.emit('beforeMultiSelect', event);
|
||||||
} else {
|
} else {
|
||||||
this.emit('beforeSelect', event);
|
this.emit('beforeSelect', event);
|
||||||
|
}
|
||||||
// 如果是右键点击,这里的mouseup事件监听没有效果
|
// 如果是右键点击,这里的mouseup事件监听没有效果
|
||||||
globalThis.document.addEventListener('mouseup', this.mouseUpHandler);
|
globalThis.document.addEventListener('mouseup', this.mouseUpHandler);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private mouseUpHandler = (): void => {
|
private mouseUpHandler = (): void => {
|
||||||
|
@ -18,14 +18,15 @@
|
|||||||
|
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
|
import type { MoveableOptions } from 'moveable';
|
||||||
import Moveable from 'moveable';
|
import Moveable from 'moveable';
|
||||||
import MoveableHelper from 'moveable-helper';
|
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 StageCore from './StageCore';
|
||||||
import StageMask from './StageMask';
|
import StageMask from './StageMask';
|
||||||
import { StageDragResizeConfig } from './types';
|
import { StageDragResizeConfig } from './types';
|
||||||
import { calcValueByFontsize, getTargetElStyle } from './util';
|
import { calcValueByFontsize, getMode, getTargetElStyle } from './util';
|
||||||
export default class StageMultiDragResize extends EventEmitter {
|
export default class StageMultiDragResize extends EventEmitter {
|
||||||
public core: StageCore;
|
public core: StageCore;
|
||||||
public mask: StageMask;
|
public mask: StageMask;
|
||||||
@ -70,19 +71,12 @@ export default class StageMultiDragResize extends EventEmitter {
|
|||||||
this.moveableForMulti?.destroy();
|
this.moveableForMulti?.destroy();
|
||||||
this.multiMoveableHelper?.clear();
|
this.multiMoveableHelper?.clear();
|
||||||
|
|
||||||
this.moveableForMulti = new Moveable(this.container, {
|
this.moveableForMulti = new Moveable(
|
||||||
|
this.container,
|
||||||
|
this.getOptions({
|
||||||
target: this.dragElList,
|
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({
|
this.multiMoveableHelper = MoveableHelper.create({
|
||||||
useBeforeRender: true,
|
useBeforeRender: true,
|
||||||
useRender: false,
|
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.destroyDragElList();
|
||||||
this.moveableForMulti.target = null;
|
this.moveableForMulti.target = null;
|
||||||
this.moveableForMulti.updateTarget();
|
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 { EventEmitter } from 'events';
|
||||||
|
|
||||||
import { Mode } from './const';
|
import { Mode, ZIndex } from './const';
|
||||||
import StageCore from './StageCore';
|
import StageCore from './StageCore';
|
||||||
import StageDragResize from './StageDragResize';
|
import StageDragResize from './StageDragResize';
|
||||||
import StageMask from './StageMask';
|
import StageMask from './StageMask';
|
||||||
@ -57,6 +57,7 @@ export default class TargetCalibrate extends EventEmitter {
|
|||||||
top: ${top}px;
|
top: ${top}px;
|
||||||
width: ${el.clientWidth}px;
|
width: ${el.clientWidth}px;
|
||||||
height: ${el.clientHeight}px;
|
height: ${el.clientHeight}px;
|
||||||
|
z-index: ${ZIndex.DRAG_EL};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
this.operationEl.id = `${prefix}${el.id}`;
|
this.operationEl.id = `${prefix}${el.id}`;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user