Vue——自定义指令

拖动指令

指令方法说明
bind

只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。

inserted

被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。

update

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

componentUpdated

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

unbind

只调用一次, 指令与元素解绑时调用。

指令属性说明
el

指令所绑定的元素,可以用来直接操作 DOM 。

binding

一个对象,包含以下属性

  • [ ] name: 指令名,不包括 v- 前缀。
  • [ ] value: 指令的绑定值, 例如: v-xxx=”1 + 1”, value 的值是 2。 相当于{{}}
  • [ ] oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
  • [ ] expression: 绑定值的字符串形式。 例如 v-xxx=”1 + 1” , expression 的值是 “1 + 1”。String类型
  • [ ] arg: 传给指令的参数。例如 v-xxx:foo, arg 的值是 “foo”。 String类型
  • [ ] modifiers: 一个包含修饰符的对象。 例如: v-xxx.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }。
  • [ ] oldVnode: 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
vnode

Vue 编译生成的虚拟节点, context指向Vue实例

定义指令逻辑

@/directive/drag,js

基本架子
export default {
  bind: (el, binding, vnode) => {
  },

  inserted: (el, binding, vnode) => {
  },

  update: (el, binding, vnode) => {
  },

  componentUpdated: (el, binding, vnode) => {
  },

  unbind: (el, binding, vnode) => {
  }
}
实现拖动
**********************************
import $ from 'jquery'
**********************************

export default {
  bind: (el, binding, vnode) => {
  },

  inserted: (el, binding, vnode) => {
  ******************************************
     // 绑定按下事件
    el.onmousedown = function (e) {             // DOM绑定点击事件
      let left = e.clientX - el.offsetLeft
      let top = e.clientY - el.offsetTop

      document.onmousemove = function (e) {     // 绑定在DOM上移动的事件
        el.style.left = e.clientX - left + 'px'
        el.style.top = e.clientY - top + 'px'
      }
      el.onmouseup = function (e) {             // DOM绑定抬起事件
         document.onmousemove = null
         el.onmouseup = null
      }
    }
  *********************************************
  },

  update: (el, binding, vnode) => {
  },

  componentUpdated: (el, binding, vnode) => {
  },

  unbind: (el, binding, vnode) => {
  }
}

此时已经实现了拖动效果,注意:绑定指令的DOM需要时绝对定位

优化划出屏幕后DOM跟随鼠标的BUG
import $ from 'jquery'

export default {
  bind: (el, binding, vnode) => {},

  inserted: (el, binding, vnode) => {
    // 绑定按下事件
    el.onmousedown = function (e) { // DOM绑定点击事件
      let left = e.clientX - el.offsetLeft
      let top = e.clientY - el.offsetTop

      document.onmousemove = function (e) { // 绑定在DOM上移动的事件
        el.style.left = e.clientX - left + 'px'
        el.style.top = e.clientY - top + 'px'
      }
      el.onmouseup = function (e) { // DOM绑定抬起事件
        document.onmousemove = null
        el.onmouseup = null
      }
    }
    *********************
    el.onmouseout = function (e) { // 绑定在DOM上移开鼠标的事件
      $(el).animate({}, 100, function () {
        $(el).css('padding', '0')
      })

      document.onmousemove = null
      el.onmouseup = null
      el.onmouseout = null
    }
    ***************************
  },

  update: (el, binding, vnode) => {},

  componentUpdated: (el, binding, vnode) => {},

  unbind: (el, binding, vnode) => {}
}

至此,已经可以通过指令绑定到DOM实现拖动,接下来我们来实现父组件控制指令状态

动态控制绑定指令状态
import $ from 'jquery'

export default {
  bind: (el, binding, vnode) => {},

  inserted: (el, binding, vnode) => {
  ********************************
    let value = binding.value
    let isAllow = typeof value.isAllow !== 'undefined' ? value.isAllow : value
    if (!isAllow) return
    *******************************
    // 绑定按下事件
    el.onmousedown = function (e) { // DOM绑定点击事件
      let left = e.clientX - el.offsetLeft
      let top = e.clientY - el.offsetTop

      document.onmousemove = function (e) { // 绑定在DOM上移动的事件
        el.style.left = e.clientX - left + 'px'
        el.style.top = e.clientY - top + 'px'
      }
      el.onmouseup = function (e) { // DOM绑定抬起事件
        document.onmousemove = null
        el.onmouseup = null
      }
    }

    el.onmouseout = function (e) { // 绑定在DOM上移开鼠标的事件
      $(el).animate({}, 100, function () {
        $(el).css('padding', '0')
      })

      document.onmousemove = null
      el.onmouseup = null
      el.onmouseout = null
    }
  },

  update: (el, binding, vnode) => {},

  componentUpdated: (el, binding, vnode) => {},

  unbind: (el, binding, vnode) => {}
}

此时如果调用时value传递为false则不会绑定指令

动态更新指令状态
import $ from 'jquery'

export default {
  bind: (el, binding, vnode) => {},

  inserted: (el, binding, vnode) => {
    let value = binding.value
    let isAllow = typeof value.isAllow !== 'undefined' ? value.isAllow : value
    if (!isAllow) return
    // 绑定按下事件
    el.onmousedown = function (e) { // DOM绑定点击事件
      let left = e.clientX - el.offsetLeft
      let top = e.clientY - el.offsetTop

      document.onmousemove = function (e) { // 绑定在DOM上移动的事件
        el.style.left = e.clientX - left + 'px'
        el.style.top = e.clientY - top + 'px'
      }
      el.onmouseup = function (e) { // DOM绑定抬起事件
        document.onmousemove = null
        el.onmouseup = null
      }
    }

    el.onmouseout = function (e) { // 绑定在DOM上移开鼠标的事件
      $(el).animate({}, 100, function () {
        $(el).css('padding', '0')
      })

      document.onmousemove = null
      el.onmouseup = null
      el.onmouseout = null
    }
  },
*****************************************
  update: (el, binding, vnode) => {
      let value = binding.value
    let isAllow = typeof value.isAllow !== 'undefined' ? value.isAllow : value

    if (!isAllow) {
      document.onmousemove = null
      el.onmousedown = null
      el.onmouseup = null
      el.onmouseout = null
    } else {
      // 绑定按下事件
      el.onmousedown = function (e) { // DOM绑定点击事件
        let left = e.clientX - el.offsetLeft
        let top = e.clientY - el.offsetTop

        $(el).animate({}, 100, function () {
          $(el).css('padding', '2px 5px')
        })

        document.onmousemove = function (e) { // 绑定在DOM上移动的事件
          el.style.left = e.clientX - left + 'px'
          el.style.top = e.clientY - top + 'px'
        }
        el.onmouseup = function (e) { // DOM绑定抬起事件
          $(el).animate({}, 100, function () {
            $(el).css('padding', '0')
          })

          document.onmousemove = null
          el.onmouseup = null
        }
      }

      el.onmouseout = function (e) { // 绑定在DOM上移开鼠标的事件
        $(el).animate({}, 100, function () {
          $(el).css('padding', '0')
        })

        document.onmousemove = null
        el.onmouseup = null
        el.onmouseout = null
      }
    }
  },
**************************************************
  componentUpdated: (el, binding, vnode) => {},

  unbind: (el, binding, vnode) => {}
}

此时在使用指令时,就可以达到动态控制指令的目的了

定义统一出口

@/directive/index.js

import drag from './drag'

export { drag }
main.js引入并挂载指令
import * as directive from '@/directive'

Vue.directive('drag', directive.drag)
项目中使用使用

Html

<div class="drags" v-drag="true">           // 自定义的指令统一通过 v-xxx 调用,接受传参
    <span>按住可以拖动我</span>
</div>

CSS

.drags {
    position: absolute;                 // 使用v-drag的DOM需要绝对定位
    z-index: 11;
    top: -50px;
    width: 120px;
    height: 30px;
    cursor: pointer;
    border: 1px solid #b50136;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值