vue自定义指令

161 阅读4分钟

需要先学习一下vue的自定义指令

Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。

举个聚焦输入框的例子

当页面加载时,该元素将获得焦点。事实上,只要你在打开这个页面后还没点击过任何内容,这个输入框就应当还是处于聚焦状态。现在让我们用指令来实现这个功能:

// 注册一个全局自定义指令`v-focus` 
Vue.directive('focus', { 
// 当被绑定的元素插入到 DOM 中时…… 
inserted: function (el) {
// 聚焦元素
el.focus() 
 }
})

如果想注册局部指令,组件中也接受一个 directives 的选项:

directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
}

钩子函数

  • bind: 只调用一次,指令第一次绑定到元素时调用,可以定义一个在绑定时执行一次的初始化动作。
  • inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
  • update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值。
  • componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
  • unbind: 只调用一次, 指令与元素解绑时调用。

钩子函数参数

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

  • binding:一个对象,包含以下 property:

    • name:指令名
    • 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 }
  • vnode:Vue 编译生成的新虚拟节点。

  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

除了 el 之外,其它参数都应该是只读的,切勿进行修改

实现几个实用的 Vue 自定义指令

  • 输入框防抖指令 v-debounce
  • 权限校验指令 v-premission
  • 拖拽指令 v-draggable

v-debounce

背景:在开发中,有些提交保存按钮有时候会在短时间内被点击多次,这样就会多次重复请求后端接口,造成数据的混乱,比如新增表单的提交按钮,多次点击就会新增多条重复的数据。

需求:防止按钮在短时间内被多次点击,使用防抖函数限制规定时间内只能点击一次。

思路:

  1. 定义一个延迟执行的方法,如果在延迟时间内再调用该方法,则重新计算执行时间。
  2. 将时间绑定在 click 方法上。
//第一步  模块化  创建一个debounce.js文件

export default {
    bind(el,bindings) {
        let timer
        el.addEventListener('click', () => {
            if (timer) {
                clearTimeout(timer)
            }
            timer = setTimeout(() => {
              bindings.value()
            }, 1000)
        })
    }
}
//在使用的地方引入  app.vue

<el-button v-has=" 'creat' " v-debounce="click">编辑</el-button>


<script>
import debounce from "@/directives/debounce";
export default{

directives:{
  debounce: debounce
},

methods:{
click() {
  console.log('focus实现了一次')
  }
 }
}
</script>

v-permission

背景:在一些后台管理系统,我们可能需要根据用户角色进行一些操作权限的判断,很多时候我们都是粗暴地给一个元素添加 v-if / v-show 来进行显示隐藏,但如果判断条件繁琐且多个地方需要判断,这种方式的代码不仅不优雅而且冗余。针对这种情况,我们可以通过全局自定义指令来处理。

需求:自定义一个权限指令,对需要权限判断的 Dom 进行显示隐藏。

思路:

  1. 自定义一个权限数组
  2. 判断用户的权限是否在这个数组内,如果是则显示,否则则移除 Dom
//第一步  模块化  创建一个has.js文件
export default {
   bind(el,bindings){
       const permission = localStorage.getItem('permissions')
       const needPermission = bindings.value
       const bool = permission.includes(needPermission)
       if(!bool){
          // el.style.display ='none' 这个只是隐藏
         //渲染是异步的
           setTimeout(()=>{
               el.parentNode.removeChild(el)
           },0)

       }
   }
}
//在使用的地方引入  app.vue


<div class="parent" style="background: pink ; height: 50px ; padding: 15px;display: flex">
<el-button v-has=" 'creat' " v-debounce="click">编辑</el-button>
<el-button v-has="'edit'">添加</el-button>
<el-button v-has="'delete'">删除</el-button>
</div>



<script>
import hasDirective from '@/directives/has'

export default{

directives:{
   has: hasDirective,
}

</script>

v-draggable

需求:实现一个拖拽指令,可在页面可视区域任意拖拽元素。

思路:

  1. 设置需要拖拽的元素为相对定位,其父元素为绝对定位。
  2. 鼠标按下(onmousedown)时记录目标元素当前的 left 和 top 值。
  3. 鼠标移动(onmousemove)时计算每次移动的横向距离和纵向距离的变化值,并改变元素的 left 和 top 值
  4. 鼠标松开(onmouseup)时完成一次拖拽
const draggable = {
  inserted: function (el) {
    el.style.cursor = 'move'
    el.onmousedown = function (e) {
      let disx = e.pageX - el.offsetLeft
      let disy = e.pageY - el.offsetTop
      document.onmousemove = function (e) {
        let x = e.pageX - disx
        let y = e.pageY - disy
        let maxX = document.body.clientWidth - parseInt(window.getComputedStyle(el).width)
        let maxY = document.body.clientHeight - parseInt(window.getComputedStyle(el).height)
        if (x < 0) {
          x = 0
        } else if (x > maxX) {
          x = maxX
        }

        if (y < 0) {
          y = 0
        } else if (y > maxY) {
          y = maxY
        }

        el.style.left = x + 'px'
        el.style.top = y + 'px'
      }
      document.onmouseup = function () {
        document.onmousemove = document.onmouseup = null
      }
    }
  },
}
export default draggable

<template>
  <div class="el-dialog" v-draggable></div>
</template>