代码语言: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);
}
}
}