天天看点

Vue的自定义指令

Vue的自定义指令

    • 简介
    • 钩子函数
    • 钩子函数参数
      • 动态指令参数
    • 函数简写
    • 对象字面量
    • 项目中使用
    • Vue源码学习目录

你越是认真生活,你的生活就会越美好

——弗兰克·劳埃德·莱特

《人生果实》经典语录

自定义指令-vue官网

简介

Vue

除了核心功能默认内置的指令 (

v-model

v-show

),Vue 也允许

注册自定义指令

注意,在

Vue2.0

中,

代码复用

抽象

的主要形式是

组件

。然而,有的情况下,你仍然需要

对普通 DOM 元素进行底层操作

,这时候就会用到

自定义指令

举个聚焦输入框的例子,如下:

Vue的自定义指令

当页面加载时,

该元素将获得焦点

(注意:

autofocus

在移动版 Safari 上不工作)。

事实上,只要你在打开这个页面后还没点击过任何内容,这个输入框就应当还是处于聚焦状态。现在让我们

用指令来实现这个功能

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

如果想注册

局部指令

,组件中也接受一个

directives

的选项:

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

然后你可以

在模板中

任何元素上使用新的

v-focus

property,如下:

钩子函数

一个指令定义对象可以提供如下几个

钩子函数

(均为可选):

  • bind

    :只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted

    被绑定元素插入父节点时

    调用 (仅保证父节点存在,但不一定已被插入文档中)。
  • update

    :所在组件的

    VNode 更新时

    调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
  • componentUpdated

    :指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  • 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 }

  • vnode

    :Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
  • oldVnode

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

除了

el

之外,

其它参数都应该是只读的

切勿进行修改

。如果需要在钩子之间

共享数据

,建议通过

元素的 dataset

来进行。

这是一个使用了这些 property 的自定义钩子样例:

Vue.directive('demo', {
  bind: function (el, binding, vnode) {
    var s = JSON.stringify
    el.innerHTML =
      'name: '       + s(binding.name) + '<br>' +
      'value: '      + s(binding.value) + '<br>' +
      'expression: ' + s(binding.expression) + '<br>' +
      'argument: '   + s(binding.arg) + '<br>' +
      'modifiers: '  + s(binding.modifiers) + '<br>' +
      'vnode keys: ' + Object.keys(vnode).join(', ')
  }
})

new Vue({
  el: '#hook-arguments-example',
  data: {
    message: 'hello!'
  }
})
           
Vue的自定义指令

动态指令参数

指令的参数可以是动态的。例如,在

v-mydirective:[argument]="value"

中,

argument

参数可以根据组件实例数据进行更新!这使得自定义指令可以在应用中被灵活使用。

例如你想要创建一个自定义指令,用来

通过固定布局将元素固定在页面上

我们可以像这样创建一个通过指令值来

更新竖直位置像素值

的自定义指令:

<div id="baseexample">
  <p>Scroll down the page</p>
  <p v-pin="200">Stick me 200px from the top of the page</p>
</div>
           
Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    el.style.top = binding.value + 'px'
  }
})

new Vue({
  el: '#baseexample'
})
           

这会

把该元素固定在距离页面顶部 200 像素

的位置。

但如果场景是我们需要把元素固定在左侧而不是顶部又该怎么办呢?这时使用

动态参数

就可以非常方便地根据每个组件实例来进行更新。

<div id="dynamicexample">
  <h3>Scroll down inside this section ↓</h3>
  <p v-pin:[direction]="200">I am pinned onto the page at 200px to the left.</p>
</div>
           
Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    var s = (binding.arg == 'left' ? 'left' : 'top')
    el.style[s] = binding.value + 'px'
  }
})

new Vue({
  el: '#dynamicexample',
  data: function () {
    return {
      direction: 'left'
    }
  }
})
           

结果如下

Vue的自定义指令

这样这个自定义指令现在的灵活性就足以支持一些不同的用例了。

函数简写

在很多时候,你可能想在

bind

update

时触发相同行为,而不关心其它的钩子。比如这样写:

Vue.directive('color-swatch', function (el, binding) {
  el.style.backgroundColor = binding.value
})
           

对象字面量

如果指令需要多个值,可以传入一个

JavaScript 对象字面量

。记住,指令函数能够接受所有合法的 JavaScript 表达式。

Vue.directive('demo', function (el, binding) {
  console.log(binding.value.color) // => "white"
  console.log(binding.value.text)  // => "hello!"
})
           

项目中使用

src/plugins/directives.js

用于权限管理,在这里主要是判断是否有对应的编辑权限,来决定相关按钮是否展示

import Vue from 'vue'
import { getAlias } from '@/utils/tool'
import store from '../store'

const directives = {
  // 权限配置
  permission: {
    inserted(el, { arg }) {
    // getAlias()方法返回登录角色的权限别名数组 arg是使用自定义组件时传入的别名 如果传入的权限别名不在数组里 就会去掉对应的元素 不展示
      if (getAlias(store.state.permissionTree).includes(arg)) return
      let parent = el.parentElement
      parent.removeChild(el)
    }
  }
}

// 全局directives
Object.keys(directives).forEach((directiveName) => {
  Vue.directive(directiveName, directives[directiveName])
})
           

src/main.js 引入

组件里使用如下(

update-account

是编辑账号的权限别名)

v-permission

自定义指令功能 如果有这个权限就正常展示div的元素,如果没有这个权限就隐藏起来

<div class="footer" v-permission:update-account>
<!--相关按钮-->
</div>
           

Vue源码学习目录

Vue源码学习完整目录

谢谢你阅读到了最后~

期待你关注、收藏、评论、点赞~

让我们一起 变得更强