前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >angular 模态框,可拖动 draggable 指令

angular 模态框,可拖动 draggable 指令

原创
作者头像
treeNewBe
修改2020-06-16 14:23:21
1.8K0
修改2020-06-16 14:23:21
举报
文章被收录于专栏:treeNewBe 学 angular
代码语言: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);
    }
  }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档