【发布时间】:2019-12-31 12:37:11
【问题描述】:
我有一个可以将盒子拖放到灰色区域的功能(请参阅stackblitz链接) 拖放框后,只能通过单击框的粉红色在灰色区域内移动框。
还添加了调整大小的功能,因此可以调整框的大小。
在添加resize指令之前,盒子只能在灰色区域内移动,但是添加resize指令后,当我们调整大小时,盒子开始移出灰色区域,问题是盒子不应该移出灰色区域调整大小时的区域
Stackblitz 链接
https://stackblitz.com/edit/angular-rgeq2p?file=src/app/hello.component.html
hello.component.html [盒子和指令应用在盒子上]
<div appMovableArea appDropzone (drop)="move(currentBox, dropzone1)">
<div *ngFor="let box of dropzone1"
appDroppable
(dragStart)="currentBox = box"
appMovable
resize>
{{ box.dis }}
</div>
</div>
盒子有 (dragStart) 输出事件发射器,它绑定到可拖动指令 ([appDroppable + draggable] 和 移动功能 appMovable、appMovableArea 指令在那里)。并且使用 Droppable.service.ts 在指令之间共享事件
(drop) 是一个输出事件发射器,使用 dropzone[appDropzone] 指令
import { Directive, ElementRef, EventEmitter, HostBinding, HostListener,
OnInit, Output, SkipSelf } from '@angular/core';
import { DroppableService } from './droppable.service';
@Directive({
selector: '[appDropzone]',
providers: [DroppableService]
})
export class DropzoneDirective implements OnInit {
@Output() drop = new EventEmitter<PointerEvent>();
@Output() remove = new EventEmitter<PointerEvent>();
private clientRect: ClientRect;
constructor(@SkipSelf() private allDroppableService: DroppableService,
private innerDroppableService: DroppableService,
private element: ElementRef) { }
ngOnInit(): void {
this.allDroppableService.dragStart$.subscribe(() =>
this.onDragStart());
this.allDroppableService.dragEnd$.subscribe(event =>
this.onDragEnd(event));
this.allDroppableService.dragMove$.subscribe(event => {
if (this.isEventInside(event)) {
this.onPointerEnter();
} else {
this.onPointerLeave();
}
});
this.innerDroppableService.dragStart$.subscribe(() =>
this.onInnerDragStart());
this.innerDroppableService.dragEnd$.subscribe(event =>
this.onInnerDragEnd(event));
}
private onPointerEnter(): void {
if (!this.activated) {
return;
}
this.entered = true;
}
private onPointerLeave(): void {
if (!this.activated) {
return;
}
this.entered = false;
}
private onDragStart(): void {
this.clientRect = this.element.nativeElement.getBoundingClientRect();
this.activated = true;
}
private onDragEnd(event: PointerEvent): void {
if (!this.activated) {
return;
}
if (this.entered) {
this.drop.emit(event);
}
}
private onInnerDragStart() {
this.activated = true;
this.entered = true;
}
private onInnerDragEnd(event: PointerEvent) {
if (!this.entered) {
this.remove.emit(event);
}
}
private isEventInside(event: PointerEvent) {
return event.clientX >= this.clientRect.left &&
event.clientX <= this.clientRect.right &&
event.clientY >= this.clientRect.top &&
event.clientY <= this.clientRect.bottom;
}
}
然后在 (dragStart) 框上输出事件发射器,该发射器存在于 draggable 指令[appDraggable] 中,它侦听指针向下事件
import { Directive, EventEmitter, HostBinding, HostListener, Output,
ElementRef } from '@angular/core';
@Directive({
selector: '[appDraggable],[appDroppable]'
})
export class DraggableDirective {
@Output() dragStart = new EventEmitter<PointerEvent>();
@Output() dragMove = new EventEmitter<PointerEvent>();
@Output() dragEnd = new EventEmitter<PointerEvent>();
constructor(public element: ElementRef) {}
@HostListener('pointerdown', ['$event'])
onPointerDown(event: PointerEvent): void {
if (event.button !== 0) {
return;
}
this.pointerId = event.pointerId;
this.dragging = true;
this.dragStart.emit(event);
}
@HostListener('document:pointermove', ['$event'])
onPointerMove(event: PointerEvent): void {
if (!this.dragging || event.pointerId !== this.pointerId) {
return;
}
this.dragMove.emit(event);
}
@HostListener('document:pointercancel', ['$event'])
@HostListener('document:pointerup', ['$event'])
onPointerUp(event: PointerEvent): void {
if (!this.dragging || event.pointerId !== this.pointerId) {
return;
}
this.dragging = false;
this.dragEnd.emit(event);
}
}
Movable 指令用于保持在灰色区域内移动 turn 使用基于可移动区域指令的计算
import { Directive, ElementRef, HostBinding, HostListener, Input } from
'@angular/core';
import { DraggableDirective } from './draggable.directive';
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
interface Position {
x: number;
y: number;
}
@Directive({
selector: '[appMovable]'
})
export class MovableDirective extends DraggableDirective {
@HostBinding('style.transform') get transform(): SafeStyle {
return this.sanitizer.bypassSecurityTrustStyle(
`translateX(${this.position.x}px) translateY(${this.position.y}px)`
);
}
@HostBinding('class.movable') movable = true;
position: Position = {x: 0, y: 0};
private startPosition: Position;
@Input('appMovableReset') reset = false;
constructor(private sanitizer: DomSanitizer, public element: ElementRef) {
super(element);
}
@HostListener('dragStart', ['$event'])
onDragStart(event: PointerEvent) {
this.startPosition = {
x: event.clientX - this.position.x,
y: event.clientY - this.position.y
}
}
@HostListener('dragMove', ['$event'])
onDragMove(event: PointerEvent) {
this.position.x = event.clientX - this.startPosition.x;
this.position.y = event.clientY - this.startPosition.y;
}
@HostListener('dragEnd', ['$event'])
onDragEnd(event: PointerEvent) {
if (this.reset) {
this.position = {x: 0, y: 0};
}
}
}
resize 指令也出现在 stackblitz 链接中。 调整大小指令的样式存在于styles.css中
【问题讨论】:
-
@jcubic ,请帮忙
-
你不能阻止一个鼠标在同一个元素上移动另一个鼠标,尝试在父元素上拖动并在子元素上调整大小。
-
@Enthu 有什么问题?我尝试调整大小,但它仍然保持边界
-
@NidhinJoseph ,当我们调整大小时,盒子开始移动并走出灰色区域,谢谢
标签: html css angular angular-directive