vue之自定义指令解析和实现拖拽和上下左右滑长按指令

注意点:bind 和 inserted

共同点: dom插入都会调用,bind在inserted之前

不同点:
    bind 时父节点为 null
    inserted 时父节点存在。
    bind是在dom树绘制前调用,inserted在dom树绘制后调用

bind: function (el) {
    console.log('bind',el.parentNode)  // null
},
inserted: function (el) {
    console.log('inserted',el.parentNode)  // <div>...</div>
}

在这里插入图片描述
在这里插入图片描述

注意:自定义指令的钩子里面没有vue实例,this指向undefined;

自定义指令的作用是用于对DOM元素进行底层操作

钩子函数

  • bind 类似于created 只调用一次,指令第一次绑定到元素时调用,此时被绑定元素在页面上还不存在;

  • inserted 类似于mounted ,被绑定元素插入到dom的时候执行,此时该元素在页面上已经存在了;

  • update 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新;

  • componentUpdated 被绑定元素所在模板完成一次更新周期时调用;

  • unbind 只调用一次,指令与元素解绑时调用;

钩子函数内的参数

  • el: 被绑定的元素,可以用来直接操作 DOM el.innerHTMLel.addEventListener

  • binding: 一个对象, 指的是指令本身 v-abc:xxx.a.b.c="abcde"

[arg] 动态指令参数

v-myDirectiveValue:[argument]="value"

在这里插入图片描述
注:具体看官网解释

未指明钩子函数时,默认bind和update中

const vm = new Vue({
            el: "#app",
            data: {
                
            },
            //自定义局部指令的时候,如果直接跟一个函数,没有写(bind inserted update)的时候,就相当于把该函数写到了bind和update中
            directives:{
                fontSize:function(el,binding){
                    el.style.fontSize = binding.value+'px'
                }
            }
        })

font-size的设置

 directives:{
        fontSize:function(el,binding){
            el.style.fontSize = binding.value+'px'
        }
 }

使用

<template>
    <div>
        <div v-fontSize='40'>牛奶</div>
    </div>
</template>
<script>

export default {
    name: 'homePage',
    components:{
        test
    },
    data() {
        return {
            test:''
        }
    },
    created(){
    },
    computed:{
    },
    methods:{
   
    },
    mounted() {
        console.log(this.$el);
        // this.$el.style.backgroundColor = "green"
    },
    directives:{
        fontSize:function(el,binding){
            el.style.fontSize = binding.value+'px'
        }
    }
}
</script>
<style lang="scss" scoped>

</style>
<style scoped>

</style>

在这里插入图片描述

PC端拖拽

// 拖拽
Vue.directive('drag', { // 全局弹窗拖拽指令
    bind: function (el, binding, vnode) {
    	console.log("parent",el.parentNode)  // null
        let oDiv = el;
        let self = vnode.context;
        oDiv.onmousedown = (e) => {
            let disX = e.clientX - oDiv.offsetLeft;
            let disY = e.clientY - oDiv.offsetTop;
            document.onmousemove = (e) => {
                let left = e.clientX - disX;
                let top = e.clientY - disY;
                // 限制拖拽在可视范围内
                if (left <= 0) {
                    left = 5; //设置成5是为了不离边缘太近
                } else if (left > document.documentElement.clientWidth - el.clientWidth) {
                    //document.documentElement.clientWidth 屏幕的可视宽度
                    left = document.documentElement.clientWidth - el.clientWidth - 5
                }
                if (top <= 0) {
                    top = 5;
                } else if (top > document.documentElement.clientHeight - el.clientHeight) {
                    top = document.documentElement.clientHeight - el.clientHeight - 5
                }
                if (!left && !top) {
                    oDiv.style.left = self.currentLeft;
                    oDiv.style.top = self.currentTop;
                } else {
                    oDiv.style.left = left + "px";
                    oDiv.style.top = top + "px";
                }
            };
            document.onmouseup = (e) => {
                document.onmousemove = null;
                document.onmouseup = null;
            };
        };
    },
    // inserted : function (el, binding, vnode) {
    //     console.log("parent",el.parentNode) 
    //     let oDiv = el;
    //     let self = vnode.context;
    //     oDiv.onmousedown = (e) => {
    //         let disX = e.clientX - oDiv.offsetLeft;
    //         let disY = e.clientY - oDiv.offsetTop;
    //         console.log("1123",disX,disY);
    //         document.onmousemove = (e) => {
    //             let left = e.clientX - disX;
    //             let top = e.clientY - disY;
    //             if (!left && !top) {
    //                 oDiv.style.left = self.currentLeft;
    //                 oDiv.style.top = self.currentTop;
    //             } else {
    //                 oDiv.style.left = left + "px";
    //                 oDiv.style.top = top + "px";
    //             }
    //         };
    //         document.onmouseup = (e) => {
    //             document.onmousemove = null;
    //             document.onmouseup = null;
    //         };
    //     };
    // },
})

移动端拖拽

全局指令写法如下

Vue.directive('drag', {
    inserted(el) {
        let switchPosition = {
            x: 10,
            y: 10,
            startX: 0,
            startY: 0,
            endX: 0,
            endY: 0
        }
        el.addEventListener('touchstart', function (e) {
            console.log(e)
            switchPosition .startX = e.touches[0].pageX
            switchPosition .startY = e.touches[0].pageY
        })
        el.addEventListener('touchend', function (e) {
            switchPosition .x = switchPosition .endX
            switchPosition .y = switchPosition .endY
            switchPosition .startX = 0
            switchPosition .startY = 0
        })
        el.addEventListener('touchmove', function (e) {
            if (e.touches.length > 0) {
                let offsetX = e.touches[0].pageX - switchPosition .startX
                let offsetY = e.touches[0].pageY - switchPosition .startY
                let x = switchPosition .x - offsetX
                let y = switchPosition .y - offsetY
                if (x + el.offsetWidth > document.documentElement.offsetWidth) {
                    x = document.documentElement.offsetWidth - el.offsetWidth
                }
                if (y + el.offsetHeight > document.documentElement.offsetHeight) {
                    y = document.documentElement.offsetHeight - el.offsetHeight
                }
                if (x < 0) {
                    x = 0
                }
                if (y < 0) {
                    y = 0
                }
                el.style.right = x + 'px'
                el.style.bottom = y + 'px'
                switchPosition .endX = x
                switchPosition .endY = y
                e.preventDefault()
            }
        })
    }
})

使用

<template>
    <div>
        <h1 v-drag class="drag"></h1>
    </div>
</template>
<script>
export default {
    name: 'homePage',
    components:{
       
    },
    data() {
        return {
            
        }
    },
    created(){
    },
    computed:{
    },
    methods:{
      
    },
    mounted() {
        console.log(this.$el);
        // this.$el.style.backgroundColor = "green"
    },
}
</script>
<style lang="scss" scoped>

</style>
<style scoped>
.drag{
    width: 200px;
    height: 200px;
    background: #ccc;
    text-align: center;
    line-height: 200px;
    color: #fff;
    cursor:move;
    position: fixed;
    z-index: 99;
    right: 10px;
    bottom: 85px;
    width: 40px;
    height: 40px;
}
</style>

在这里插入图片描述
在这里插入图片描述

移动端上下左右滑长按

Vue.directive('touch', {
	// 滑动指令
    bind: function (el, binding, vnode) {
      // 传入参数滑动模式 press swipeRight swipeLeft swipeTop swipeDowm
      var touchType = binding.arg; 
      var timeOutEvent = 0;
      var direction = '';
      // 滑动处理
      var startX, startY;

      // 返回角度
      function GetSlideAngle(dx, dy) {
        return Math.atan2(dy, dx) * 180 / Math.PI;
      }

      // 根据起点和终点返回方向 1:向上,2:向下,3:向左,4:向右,0:未滑动
      function GetSlideDirection(startX, startY, endX, endY) {
        var dy = startY - endY;
        var dx = endX - startX;
        var result = 0;

        // 判断滑动距离, 如果滑动距离太短
        if (Math.abs(dx) < 2 && Math.abs(dy) < 2) {
          return result;
        }
		// 判断滑动角度
        var angle = GetSlideAngle(dx, dy);
        if (angle >= -45 && angle < 45) {
          result = 'swipeRight';
        } else if (angle >= 45 && angle < 135) {
          result = 'swipeUp';
        } else if (angle >= -135 && angle < -45) {
          result = 'swipeDown';
        }
        else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
          result = 'swipeLeft';
        }
        return result;
      }
      // 监听开始
      el.addEventListener('touchstart', function (ev) {
        startX = ev.touches[0].pageX;
        startY = ev.touches[0].pageY;

        //判断长按操作
        timeOutEvent = setTimeout(() =>{
          timeOutEvent = 0 ;
          if(touchType === 'press'){
              binding.value()
          }
        } , 500);

      }, false);
      
	  // 监听移动
      el.addEventListener('touchmove' , function (ev) {
        clearTimeout(timeOutEvent)
        timeOutEvent = 0;
      });
      
	  // 监听结束
      el.addEventListener('touchend', function (ev) {
        var endX, endY;
        endX = ev.changedTouches[0].pageX;
        endY = ev.changedTouches[0].pageY;
        direction = GetSlideDirection(startX, startY, endX, endY);

        clearTimeout(timeOutEvent)

        switch (direction) {
          case 0:
            break;
          case 'swipeUp':
            if(touchType === 'swipeUp'){
                binding.value()
            }
            break;
          case 'swipeDown':
            if(touchType === 'swipeDown'){
                binding.value()
            }
            break;
          case 'swipeLeft':
            if(touchType === 'swipeLeft'){
                binding.value()
            }
            break;
          case 'swipeRight':
            if(touchType === 'swipeRight'){
                binding.value()
            }
            break;
          default:
        }
  		}, false);
    }
})

使用指令

 <div
      v-touch:swipeLeft="leftSlide"
      v-touch:swipeRight="rightSlide"
      v-touch:swipeUp="upSlide"
      v-touch:swipeDown="downSlide"
      v-touch:press="press"
      class="slide"
  ></div>

   leftSlide() {
      console.log("左滑");
    },
    rightSlide() {
      console.log("右滑");
    },
    upSlide() {
      console.log("上滑");
    },
    downSlide() {
      console.log("下滑");
    },
    press() {
      console.log("长按");
    },
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值