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

标签 angular bootstrap-4 bootstrap-modal angular8 ng-bootstrap

我正在尝试将 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 使 div 位于左、右、上、下和四个 Angular 的位置

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

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

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

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

我们需要将 ElementRef 指定为输入来拖动“模态”

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

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

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 中的光标,我们需要添加类

.cell-top {
  cursor: move;
}

关于angular - ngBootstrap Angular 8 - 模态可调整大小和可拖动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68525239/

相关文章:

AoT 编译中的 Angular2 主机绑定(bind)问题

javascript - Angular 2+ 中 setTimeout 的替代方案

javascript - 如何仅在选择某个下拉菜单项时激活输入字段

jquery - 尽管安装了 JQuery 和 Bootstrap,但工具提示仍不起作用

javascript - 单击饼图切片时,Bootstrap 模式不显示

javascript - UI Bootstrap Datepicker 弹出窗口不适用于 Modal 和 ControllerAs

javascript - 如何在 ngrx/effect (redux-observable) 中分派(dispatch)多个 Action ?

javascript - 获取 *ngFor 中的文本长度

javascript - Bootstrap 混合下拉菜单切换

javascript - 通过 Google Maps API 显示 Bootstrap 登录模式