场景:页面一个div框,或者工具框,需要实现拖拽,不用固定
1.指令文件
import { Directive, ElementRef, HostListener, Input, Output, EventEmitter, OnInit } from '@angular/core';
import * as $ from 'jquery';
@Directive({
selector: '[appDraggable]'
})
export class DraggableDirective {
@Output() mouseEnter = new EventEmitter<boolean>();
element: any = null;
private disX = 0;
private disY = 0;
private isDown = false;
private parentDiv;
constructor(private ref: ElementRef) {
// console.log(ref);
this.element = this.ref.nativeElement;
}
@HostListener('drag', ['event'])
dragEvent(): void {
// console.log('drag');
}
@HostListener('mouseenter', ['$event']) // 一个装饰器,用于声明要监听的 DOM 事件,并提供在该事件发生时要运行的处理器方法。
onMouseEnter(ev: any): void {
ev.stopPropagation();
// console.log('拖拽-移入');
this.mouseEnter.emit(true);
}
@HostListener('mouseleave', ['$event'])
onMouseLeave(ev: any): void {
ev.stopPropagation();
// console.log('拖拽-移出');
document.onmousemove = null;
document.onmouseup = null;
this.isDown = false;
this.changeDownStyle();
this.mouseEnter.emit(false);
}
// 1.是否为顶级
isParent(obj, parentObj): any {
// 判断当前存不存在,是不是body,并且是不是点的这个dom
if (obj !== undefined &&
obj != null &&
obj.tagName.toUpperCase() !== 'BODY') {
if (obj === parentObj) {
return { ifContain: true, evDom: parentObj };
} else {
// 判断当前点击的父级是否包含当前有拖拽的元素
const parAll = $(obj).parents();
let ifContain = false;
// tslint:disable-next-line:prefer-for-of
for (let i = 0; i < parAll.length; i++) {
const element = parAll[i];
if (element === parentObj) {
ifContain = true;
break;
}
}
if (ifContain) {
return { ifContain, evDom: parentObj };
} else {
return { ifContain };
}
}
} else {
return { ifContain: false };
}
}
// 点击事件 按下鼠标时,获取当前的定位
@HostListener('document:mousedown', ['$event'])
onMouseDown(ev: any): void {
ev.stopPropagation();
// console.log('按下鼠标');
const isParent = this.isParent(ev.target, this.element);
if (isParent.ifContain) {
let evParentNode = ev.target.parentNode;
// 判断当前点击的dom,是否在当前拖拽的dom中,如果是,那么就直接获取当前绑定拖拽的dom元素
if (isParent.evDom) {
evParentNode = isParent.evDom.parentNode;
}
// 获取当前点击的div相对的父级div;(注意:这里的父级一定要是最顶级那种,宽100%,长100%,否则无效)
if (evParentNode && evParentNode.clientHeight > 0 && evParentNode.clientWidth > 0) {
this.parentDiv = evParentNode;
} else {
this.parentDiv = document.querySelector('body');
}
this.disX = ev.clientX - this.element.offsetLeft;
this.disY = ev.clientY - this.element.offsetTop;
// 移动区域
this.isDown = true;
this.changeDownStyle();
}
}
/**
* 监听document移动事件事件 鼠标移动时
*/
@HostListener('document:mousemove', ['$event'])
onMouseMove(ev: any): void {
ev.stopPropagation();
if (this.isDown) {
// console.log('开始移动');
// 获取父元素的宽高
const cw = this.parentDiv.clientWidth;
const cy = this.parentDiv.clientHeight;
// 当前块的宽高
const dw = this.element.offsetWidth;
const dh = this.element.offsetHeight;
let oLeft = ev.clientX - this.disX;
let oTop = ev.clientY - this.disY;
// top定位位置
if (oTop < 0) {
oTop = 0;
} else if (oTop >= cy - dh) {
oTop = cy - dh;
}
// left定位位置
if (oLeft < 0) {
oLeft = 0;
} else if (oLeft >= cw - dw) {
oLeft = cw - dw;
}
this.element.style.left = oLeft + 'px';
this.element.style.top = oTop + 'px';
}
}
// 监听document离开松手事件
@HostListener('document:mouseup', ['$event'])
onMouseup(ev: any): void {
ev.stopPropagation();
// console.log('移除');
if (this.isDown) {
document.onmousemove = null;
document.onmouseup = null;
this.isDown = false;
this.changeDownStyle();
}
}
// 样式改变
changeDownStyle(): void {
if (this.isDown) {
$(this.element).css({
border: '1px solid rgb(0, 229, 255)',
background: 'linear-gradient(90deg, #0057cd 0%, #007da4 100%)',
cursor: 'move',
});
} else {
$(this.element).css({ border: '1px solid #00aaff', background: 'rgba(0, 42, 127, 0.6)', cursor: 'default', });
}
}
}
2.导入module
import { DraggableDirective } from '../_directives/draggable.directive';
.
.
.
declarations: [
DraggableDirective,
]
.
.
.
3.页面实现,只需要在拖拽的div上加上appDraggable标签即可
<div id="myScreenDiv1" appDraggable>
</div>
网友评论