自定义anglular拖拽指令

2022-11-28  本文已影响0人  甘道夫老矣

场景:页面一个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>
上一篇下一篇

猜你喜欢

热点阅读