使用Vue实现自定义拖拽指令(v-drag)

自定义指令基础语法

注册一个全局自定义指令 v-drag,基本语法

Vue.directive('drag', { 
  //钩子函数 
})

钩子函数

一个指令定义对象可以提供如下几个钩子函数 (均为可选):

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
  • update
  • componentUpdated
  • unbind

钩子函数的参数 (即 el、binding、vnode 和 oldVnode)。

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下 property:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive=“1 + 1” 中,绑定值为 2。
    • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive=“1 + 1” 中,表达式为 “1 + 1”。
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 “foo”。
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。

代码演示

1.创建v-drag.js(向外暴露一个函数或对象,对象需要有install方法)

var baseZindex = 999;
var index = 0;
var max =0;

//Vue.use() 的果插件是一个对象时,必须提供 install 方法。
//如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。
let vDrag = function (Vue, options = {
     
     }) {
    
    
    /** @namespace options.directiveName */
    // 指令名字 在vue.use中作为参数指定
    let name = options.directiveName || 'drag';

    //注册一个全局自定义指令 `v-drag`,基本语法Vue.directive('drag', {  钩子函数 })
    //钩子函数 bind:只调用一次,指令第一次绑定到元素时调用。
    //指令钩子函数会被传入以下参数:el、binding等。el:指令所绑定的元素,可以用来直接操作 DOM。binding:一个对象,只读,切勿进行修改

    Vue.directive(name, {
    
    
        bind (el, binding) {
    
    
            var odiv =el;
            var disX = 0;//鼠标相对元素的位置
            var disY = 0;//鼠标相对元素的位置
            var curClientX; //鼠标指针坐标
            var curClientY;//鼠标指针坐标

            //getAttribute() 方法返回指定属性名的属性值。
            var isFixed=el.getAttribute("fixed")!=null;

            //getElementsByClassName() 方法返回文档中所有指定类名的元素集合,是一个数组
            var handle = el.getElementsByClassName('v-drag-handle').length>0?el.getElementsByClassName('v-drag-handle')[0]:el;

            var zindexEnable=el.getAttribute("zindexEnable");
            if(zindexEnable){
    
    
                el.setAttribute('data-zindex',index);
                el.style.zIndex = baseZindex + index;
            }


            // 记录长度,index最后是个固定值
            index++;
            // 保存最大值,默认没点击时,最大值就是最后一个,max是根据点击动态变化
            max = index;


            handle.addEventListener('mousedown', mouseDownHandle);
            document.addEventListener('mouseup',mouseUpHandle);
            //------------------------------------鼠标抬起事件
            function mouseUpHandle () {
    
    
                document.removeEventListener('mousemove',mouseMoveHandle);
            }
            //------------------------------------鼠标点击事件
            function mouseDownHandle (e) {
    
    
                if(zindexEnable){
    
    
                    if (el.getAttribute('data-zindex') < max) {
    
    
                        el.setAttribute('data-zindex', ++max - 1);
                        el.style.zIndex = baseZindex + max - 1;
                    }
                }
                // clientX/Y    事件属性返回当事件被触发时鼠标指针相对于浏览器页面(或客户区)的水平坐标
                // offsetLeft   可以判断一个物体的跟document的左边距离,也就是浏览器左边缘
                // getBoundingClientRect用于获取某个元素相对于视窗的位置集合。
                // 这个方法返回一个矩形对象,包含四个属性:left、top、right和bottom。分别表示元素各边与页面上边和左边的距离。

                curClientX=e.clientX;
                curClientY=e.clientY;
                // 算出鼠标相对元素的位置
                if(isFixed){
    
    
                    var rect=el.getBoundingClientRect();
                    disX = e.clientX - rect.left;
                    disY = e.clientY - rect.top;
                } else{
    
    
                    disX = e.clientX - odiv.offsetLeft;
                    disY = e.clientY - odiv.offsetTop;
                }
                //这里的拖动事件只能绑定在外层上,否则快速拖动会有问题
                document.addEventListener('mousemove', mouseMoveHandle);
            }
            //------------------------------------鼠标移动事件
            function mouseMoveHandle (e) {
    
    
                var offsetX=curClientX-e.clientX;//鼠标与上一次的位置差
                var offsetY=curClientY-e.clientY;
                if(offsetX==0&&offsetY==0) return;
                let left = e.clientX - disX;
                let top = e.clientY - disY;
                // 移动当前元素
                if(isFixed){
    
    
                    if (odiv.style.position !== 'fixed') {
    
    
                        odiv.style.position = 'fixed';
                    }
                } else{
    
    
                    if (odiv.style.position !== 'absolute') {
    
    
                        odiv.style.position = 'absolute';
                    }
                }
                odiv.style.left = left + 'px';
                odiv.style.top = top + 'px';
                odiv.style.bottom ="auto";
                odiv.style.right = "auto";
            }

        }
    })
};

export default vDrag

2.main.js中引入

import vDrag from "./v-drag.js"
//Vue.use: 如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。
Vue.use(vDrag,{directiveName:'drag'});

3.使用

<div class="u-img-background" v-drag>

猜你喜欢

转载自blog.csdn.net/weixin_46769087/article/details/131551048
今日推荐