我正在尝试在Angular 7中创建可移动窗口。为此,我有一个绝对定位的div,窗口将进入其中。我有一个app-window-toolbar组件和一个app-window-container组件。拖动工具栏时,我想更改app-window-container组件的顶部和左侧CSS属性。 app-window-toolbar组件是app-window-container组件的子代。
app.component.html
<app-window-container *ngFor="let window of windows">
<app-window-toolbar>
</app-window-toolbar>
<div>Window content here</div>
</app-window-container>
window-toolbar.component.ts
@Component({
selector: "app-window-toolbar",
templateUrl: "./window-toolbar.component.html",
styleUrls: ["./window-toolbar.component.scss"]
})
export class WindowToolbarComponent implements OnInit {
moving = false
constructor(private elRef: ElementRef) { }
ngOnInit() {
}
startMove() {
this.moving = true
}
@HostListener("document:mousemove", ["$event"])
move(event: MouseEvent) {
if (this.moving) {
// Here I'm trying to access the parent element to set it's
// CSS properties. The mouse y position is being logged
// successfully, but the parent elements style is not being set.
console.log("mouse y: " + event.clientY)
this.elRef.nativeElement.parentElement.style.top = event.clientY
this.elRef.nativeElement.parentElement.style.left = event.clientX
}
}
@HostListener("document:mouseup")
stopMove() {
this.moving = false
}
}
window-toolbar.component.html
<div style="height: 100%; display: flex" (mousedown)="startMove()">
<div style="flex-grow: 1">
<ng-content></ng-content>
</div>
<div style="height: 100%">
<i class="material-icons md-light close-window-icon">close</i>
</div>
</div>
我不确定我在哪里出错。我也在寻找有关是否这是最佳方法的反馈?从我读过的内容来看,这种DOM操作风格似乎不被接受,但是我不确定实现这一功能的选择余地很大。我唯一想到的另一件事就是拖动工具栏时发出事件,并让容器侦听这些事件。不确定性能会如何。
答案 0 :(得分:1)
我想这是行不通的,因为style.top|left
属性应采用px
值,但您要设置数字。
this.elRef.nativeElement.parentElement.style.top = event.clientY + 'px'
/\
don't forget it
此外,如果您不希望工具栏在开始拖动时跳转,则应考虑到光标和该工具栏左上角之间的偏移。
shift = {
x: 0,
y: 0
}
startMove(e) {
const position = getPosition(e.currentTarget);
this.shift = {
x: e.pageX - position.left,
y: e.pageY - position.top
}
this.moving = true
}
move(event: MouseEvent) {
if (this.moving) {
this.elRef.nativeElement.parentElement.style.top = (event.clientY - this.shift.y) + 'px'
this.elRef.nativeElement.parentElement.style.left = (event.clientX - this.shift.x) + 'px'
}
}
function getPosition(elem) {
const box = elem.getBoundingClientRect();
return {
top: box.top + pageYOffset,
left: box.left + pageXOffset
};
}
答案 1 :(得分:0)
正如评论中指出的那样,Angular Material中已经有一个模块可以解决此问题。当您开始考虑边缘情况时,我决定采用此解决方案,因此推出自己的解决方案是没有意义的。
执行以下操作很容易创建可拖动的窗口:
注册DragDropModule:
import {DragDropModule} from '@angular/cdk/drag-drop';
@NgModule({
declarations: [],
imports: [
DragDropModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
在布局中使用指令:
<div class="app-layout mat-typography">
<div class="app-menu"></div>
<div class="app-content">
<div *ngFor="let window of windows" class="window-container" cdkDrag cdkDragBoundary=".app-content">
<div class="window-toolbar" cdkDragHandle></div>
<div class="window-content"></div>
</div>
</div>
</div>