ngBootstrap Angular 8 - 模态可调整大小和可拖动

ngBootstrap Angular 8 - Modal Resizable and Draggable

我正在尝试将 bootstrap https://ng-bootstrap.github.io/#/components/modal/examples 版本 4 与 Angular 8 一起使用。我想让模态可调整大小并可拖动。我看到了一些其他版本的例子,比如 3.xx 但 angular - http://jsfiddle.net/GDVdN/

Bootstrap4 的任何参考 ANgular 8 - 模态可调整大小 + 可拖动?

我最接近的是创建一个组件,使内部的任何元素“可调整大小”。

更新:“玩”“modal-dialog”风格

想象一下这样的组件

<div class="resizable" [ngStyle]="style">
  <ng-content></ng-content>
  <div class="cell-border-top"></div>
  <div class="cell-border-bottom"></div>
  <div class="cell-border-left"></div>
  <div class="cell-border-right"></div>
  <div class="cell-top-right"></div>
  <div class="cell-bottom-right"></div>
  <div class="cell-top-left"></div>
  <div class="cell-bottom-left"></div>
</div>

.css 使得divs 是左、右、上、下和四个角的位置

我们监听 mouseDown,并“获取”class我们可以将拖动类型存储在变量中的名称

export enum TypeDrag {
  Move,
  Top,
  Bottom,
  Left,
  Right,
  TopRight,
  BottomRight,
  TopLeft,
  BottomLeft
}

当鼠标按下时,我们订阅 mouseUp 和 mouseMove,mouseUp 简单地删除对 mouseMove 的订阅

mouseMove改变样式div改变位置和尺寸

我们需要将 ElementRef 指定为 Input 以拖动“modal”

还有一个额外的考虑是 ngb-modal 将模态更改为“margin-left”和“margin-top”,所以我需要将 margin 设置为 0 到 a div 带有 calssName==“模态对话框”。为此,我们创建一个递归函数

为了获得“模态对话框”,我们使用递归函数

findModalContent(element:HTMLElement)
{
  return element.className=="modal-dialog"?element:
            element.parentElement?this.findModalContent(element.parentElement):
            null
}

我尽量在代码中用注释来解释

通常这是 stackblitz

@Component({
  selector: 'angular-window',
  templateUrl: './angular-window.component.html',
  styleUrls: ['./angular-window.component.css']
})
export class AngularWindowComponent implements OnInit {
  rect: any;
  incr: number[] = [0, 0, 0, 0];
  nativeElement: any;
  typeDrag: TypeDrag;
  origin: any;
  onDrag: boolean = false;
  moveSubscription: any;
  //div: any;  <--remove in the updated

  classNames = [
    'cell-top',
    'cell-border-top',
    'cell-border-bottom',
    'cell-border-left',
    'cell-border-right',
    'cell-top-right',
    'cell-bottom-right',
    'cell-top-left',
    'cell-bottom-left'
  ];

  style: any = null;
  constructor(private elementRef: ElementRef) {}

  @Input() set dragHolder(value) { //the drag holder will be a 
                                   //template reference variable
                                   //we add the class "cell-top"

    value.classList.add("cell-top");
  }

  /*It's not necesary now
  //I need indicate the background-color
  @Input('background-color') backgroundColor = 'white';
  */

  ngOnInit(): void {

    //get the "modalContent"
        this.modalContent=this.findModalContent(this.elementRef.nativeElement)

    //we subscribe to mouseDown
    fromEvent(this.elementRef.nativeElement, 'mousedown')
      .pipe(
        //we filter, only get if the className of element 
        //is one of the indicate by the variable "classNames"
        //or if the className include the "cell-top"

        filter((event: MouseEvent) => {
          const classs = (event.target as any).className;
          if (classs && typeof classs === 'string') {
            const className = classs.split(' ');
            return className.indexOf("cell-top")>=0?true:
              this.classNames.indexOf(classs) >= 0;
          }
          return false;
        })
      )
      .subscribe((event: MouseEvent) => {

        this.div = this.elementRef.nativeElement.childNodes[0];
        this.rect = this.div.getBoundingClientRect();
        this.origin = { x: event.screenX, y: event.screenY };

        this.onDrag = true;

        const className = (event.target as any).className.split(' ');
        this.typeDrag =className.indexOf('cell-top')>=0?TypeDrag.Move:
         (this.classNames.indexOf(className[0])) as TypeDrag;

        //acording the typeDrag, I store in "this.incr" the move
          
        this.incr =
          this.typeDrag == TypeDrag.Move
            ? [1, 0, 1, 0]
            : this.typeDrag == TypeDrag.Top
            ? [1, -1, 0, 0]
            : this.typeDrag == TypeDrag.Bottom
            ? [0, 1, 0, 0]
            : this.typeDrag == TypeDrag.Right
            ? [0, 0, 0, 1]
            : this.typeDrag == TypeDrag.Left
            ? [0, 0, 1, -1]
            : this.typeDrag == TypeDrag.TopRight
            ? [1, -1, 0, 1]
            : this.typeDrag == TypeDrag.TopLeft
            ? [1, -1, 1, -1]
            : this.typeDrag == TypeDrag.BottomRight
            ? [0, 1, 0, 1]
            : [0, 1, 1, -1];

        this.onDrag = true;

        /*Not necesary
        //remove the "margin" in modal-dialog
        const modalContent=this.findModalContent(this.div.parentElement)
        if (modalContent)
          modalContent.style.margin=0;
        */

        //we subscribe to mouseUp    
        fromEvent(document, 'mouseup')
          .pipe(take(1))
          .subscribe(() => {
            if (this.moveSubscription) {
              this.moveSubscription.unsubscribe();
              this.moveSubscription = undefined;
              this.onDrag = false;
            }
          });

        //we subscribe to mouseMove

        if (!this.moveSubscription) {
          this.moveSubscription = fromEvent(document, 'mousemove').pipe(
            startWith({screenY:this.origin.y,screenX:this.origin.x})
          ).subscribe(
            (moveEvent: MouseEvent) => {
              const incrTop = moveEvent.screenY - this.origin.y;
              const incrLeft = moveEvent.screenX - this.origin.x;
              const width = this.rect.width + this.incr[3] * incrLeft;
              const heigth = this.rect.height + this.incr[1] * incrTop;
              /*before
              this.style = {
                position: 'absolute',
                'z-index': 1051,
                'background-color': this.backgroundColor,
                top: this.rect.top + this.incr[0] * incrTop + 'px',
                height: (heigth < 75 ? 75 : heigth) + 'px',
                left: this.rect.left + this.incr[2] * incrLeft + 'px',
                width: (width < 50 ? 50 : width) + 'px'
              };
              */
              //now:
              this.modalContent.style['max-width']=
                        (width < 50 ? 50 : width) + 'px'
              this.modalContent.style['margin-top']=
                        this.rect.top + this.incr[0] * incrTop + 'px'
              this.modalContent.style['margin-left']=
                        this.rect.left + this.incr[2] * incrLeft + 'px'
              this.style={
                 width:(width < 50 ? 50 : width-1) + 'px',
                 height:(heigth < 75 ? 75 : heigth-1) + 'px'
              }
      });
  }
}

使用简单,例如(查看如何指示“dragHolder”)

<ng-template #content let-modal>
  <angular-window [dragHolder]="header">
    <div class="modal-header">
      <h4 #header class="modal-title w-100" 
           id="modal-basic-title">Profile update</h4>
    </div>
    <div class="modal-body">
    </div>
    <div class="modal-footer">
    </div>
  </angular-window>
</ng-template>

注意:要更改 dragHolder 中的光标,我们需要添加 class

.cell-top {
  cursor: move;
}