多选优化及问题修复 (#196)

* feat(stage): 支持绝对定位,固定定位,组内元素按住shift键进行多选拖拽能力

* feat(stage): 使用moveable.helper接管moveable target的更新,针对弹窗场景引入业务方方法进行校准

* feat(stage): 将多选逻辑封装到StageMultiDragResize

* fix(stage): 修复多选target元素无法映射到drag虚拟元素的问题

* feat(stage): 多选拖拽完成后将更新的位置信息暴露给上层业务方

* fix(stage): 删除多余的成员变量

Co-authored-by: parisma <parisma@tencent.com>
This commit is contained in:
khuntoriia 2022-07-22 11:31:11 +08:00 committed by GitHub
parent fe520bf600
commit 3ccabfbe44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 16 deletions

View File

@ -141,6 +141,10 @@ export default class StageCore extends EventEmitter {
.on('sort', (data: UpdateEventData) => {
setTimeout(() => this.emit('sort', data));
});
this.multiDr.on('update', (data: UpdateEventData) => {
setTimeout(() => this.emit('update', data));
});
}
public getElementsFromPoint(event: MouseEvent) {

View File

@ -53,14 +53,8 @@ export default class StageDragResize extends EventEmitter {
public target?: HTMLElement;
/** 目标节点在蒙层中的占位节点 */
public dragEl?: HTMLDivElement;
/** 多选:目标节点组 */
public targetList: HTMLElement[] = [];
/** 多选:目标节点在蒙层中的占位节点组 */
public dragElList: HTMLDivElement[] = [];
/** Moveable拖拽类实例 */
public moveable?: Moveable;
/** Moveable多选拖拽类实例 */
public moveableForMulti?: Moveable;
/** 水平参考线 */
public horizontalGuidelines: number[] = [];
/** 垂直参考线 */

View File

@ -25,7 +25,7 @@ import { DRAG_EL_ID_PREFIX } from './const';
import StageCore from './StageCore';
import StageMask from './StageMask';
import { StageDragResizeConfig } from './types';
import { getTargetElStyle } from './util';
import { calcValueByFontsize, getTargetElStyle } from './util';
export default class StageMultiDragResize extends EventEmitter {
public core: StageCore;
public mask: StageMask;
@ -88,7 +88,7 @@ export default class StageMultiDragResize extends EventEmitter {
useRender: false,
createAuto: true,
});
const frames: { left: number; top: number; dragLeft: number; dragTop: number; id: string }[] = [];
const frames: { left: number; top: number; id: string }[] = [];
this.moveableForMulti
.on('dragGroupStart', (params) => {
const { events } = params;
@ -96,15 +96,13 @@ export default class StageMultiDragResize extends EventEmitter {
// 记录拖动前快照
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;
const matchEventTarget = this.targetList.find(
(targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
);
if (!matchEventTarget) return;
frames.push({
left: matchEventTarget.offsetLeft,
top: matchEventTarget.offsetTop,
dragLeft: dragEventTarget.offsetLeft,
dragTop: dragEventTarget.offsetTop,
id: matchEventTarget.id,
});
});
@ -113,9 +111,13 @@ export default class StageMultiDragResize extends EventEmitter {
const { events } = params;
// 拖动过程更新
events.forEach((ev) => {
const frameSnapShot = frames.find((frameItem) => frameItem.id === ev.target.id.split('_')[2]);
const frameSnapShot = frames.find(
(frameItem) => frameItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
);
if (!frameSnapShot) return;
const targeEl = this.targetList.find((targetItem) => targetItem.id === ev.target.id.split('_')[2]);
const targeEl = this.targetList.find(
(targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
);
if (!targeEl) return;
// 元素与其所属组同时加入多选列表时,只更新父元素
const isParentIncluded = this.targetList.find((targetItem) => targetItem.id === targeEl.parentElement?.id);
@ -126,6 +128,9 @@ export default class StageMultiDragResize extends EventEmitter {
}
});
this.multiMoveableHelper?.onDragGroup(params);
})
.on('dragGroupEnd', () => {
this.update();
});
}
@ -153,4 +158,28 @@ export default class StageMultiDragResize extends EventEmitter {
public destroyDragElList(): void {
this.dragElList.forEach((dragElItem) => dragElItem?.remove());
}
/**
*
* @param isResize
*/
private update(isResize = false): void {
if (this.targetList.length === 0) return;
const { contentWindow } = this.core.renderer;
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 },
});
});
}
}