angular 模态框,可拖动 draggable 指令

2020-06-16 14:23:21 浏览数 (2)

代码语言:typescript复制
import { Directive, ElementRef, OnInit, Input, Renderer2, RendererStyleFlags2 } from '@angular/core';

/**
 * @param area 要拖动的元素
 * @param handle 要拖动的元素头部句柄
 * @option maskClass 外层模态框的 class
 * @option hidden 外层模态框 overflow 是否强制 hidden
 */
export interface Draggable {
  area: string;
  handle: string;
  maskClass?: string;
  hidden?: boolean;
}
/**
 * @selector: [draggable]
 * @example [draggable] = '{area: Selector, handle: Selector, maskClass: string, hidden: boolean}'
 * @param area 要拖动的元素
 * @param handle 要拖动的元素头部句柄
 * @option maskClass 外层模态框的 class
 * @option hidden 外层模态框 overflow 是否强制 hidden, 默认true
 */
@Directive({
  // tslint:disable-next-line:directive-selector
  selector: '[draggable]'
})
export class DraggableDirective implements OnInit {
  constructor(private el: ElementRef, private render: Renderer2) { }
  @Input() draggable: Draggable ;
  get resizing(): boolean | string {
    return this.el.nativeElement.getAttribute('resizing');
  }
  /**
   * 要拖动的元素
   */
  area = null;
  /**
   * 要拖动的元素头部句柄
   */
  handle = null;
  /**
   * 是否可以移动
   */
  canMove = false;
  distanceX = 0;
  distanceY = 0;
  /**
   * 寻找层级,默认为5
   */
  maxFloor = 5;
  /**
   * 模态框
   */
  maskWrap = null;
  ngOnInit(): void {
    if (this.draggable.maskClass === undefined) { // 如果没传,默认ant-modal-wrap
      this.draggable.maskClass = 'ant-modal-wrap';
    }
    if (this.draggable.hidden === undefined) { // 如果没传,默认true
      this.draggable.hidden = true;
    }
    this.getElement();
  }
  /**
   * 根据指令传入的参数,找到所需的元素
   * @param isGet 是否找到
   * @description 如果找到,就初始化
   */
  getElement(isGet = false) {
    if (isGet) {
      this.init();
      return true;
    }
    setTimeout(() => {
      if (this.draggable.hasOwnProperty('area')) {
        this.area = this.el.nativeElement.querySelector(this.draggable.area);
        this.handle = this.el.nativeElement.querySelector(this.draggable.handle);
      } else {
        this.area = this.el.nativeElement;
        this.handle = this.el.nativeElement.querySelector(this.draggable.handle);
      }
      this.getElement(!!(this.area && this.handle));
    }, 500);
  }
  /**
   * 初始化,并监听鼠标事件
   */
  init() {
    if (this.area === this.handle) {
      this.render.setStyle(this.area, 'position', 'fixed');
    } else {
      this.render.setStyle(this.area, 'position', 'absolute');
      this.render.setStyle(this.area, 'width', '100%');
    }
    this.render.listen(this.handle, 'mousedown', (e: MouseEvent) => {
      this.canMove = true;
      this.distanceX = e.clientX - this.area.offsetLeft;
      this.distanceY = e.clientY - this.area.offsetTop;
      if (this.handle.hasOwnProperty('setCapture')) {
        this.handle.setCapture();
      }
      this.getMaskWrap(this.area);
    });
    this.render.listen(document, 'mousemove', (e: MouseEvent) => {
      if (this.canMove && !this.resizing) {
        this.area.style.left = e.clientX - this.distanceX   'px';
        this.area.style.top = e.clientY - this.distanceY   'px';
      }
    });
    this.render.listen(document, 'mouseup', (e: MouseEvent) => {
      this.canMove = false;
      this.clearMaskOverflow();
      if (this.handle.hasOwnProperty('releaseCapture')) {
        this.handle.releaseCapture();
      }
    });
  }
  /**
   * 获取Mask
   * @param el Mask的子元素
   * @description 寻找层级maxFloor,默认为5;如果已经找到过,就直接不运行
   */
  getMaskWrap(el: any) {
    if (this.maskWrap) { return true; }
    const parentNode = this.render.parentNode(el);
    if (this.maxFloor > 0) {
      for (const className of parentNode.classList) {
        if (className === this.draggable.maskClass) {
          this.maskWrap = parentNode;
          this.setMask2OverflowHidden();
          this.maxFloor = 5;
          return true;
        }
      }
      this.maxFloor--;
      this.getMaskWrap(parentNode);
    } else {
      this.maxFloor = 5;
      return false;
    }
  }
  /**
   * 设置Mask的overflow hidden
   * @param node 要设置的overflow:hidden的Mask
   */
  setMask2OverflowHidden() {
    this.render.setStyle(this.maskWrap, 'overflow', 'hidden', RendererStyleFlags2.Important);
  }
  /**
   * 清除Mask的overflow
   */
  clearMaskOverflow() {
    if (this.maskWrap && this.draggable.hidden === false) {
      this.render.setStyle(this.maskWrap, 'overflow', null);
    }
  }
}

0 人点赞