在Angular 7中制作可移动Windows

时间:2019-04-03 03:43:43

标签: angular typescript

我正在尝试在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操作风格似乎不被接受,但是我不确定实现这一功能的选择余地很大。我唯一想到的另一件事就是拖动工具栏时发出事件,并让容器侦听这些事件。不确定性能会如何。

2 个答案:

答案 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
  };
}

Ng-run Example

答案 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>