Skip to content
本页目录

directive 指令

介绍

主要作用是对 dom 元素进行底层的操作。如 vue 自带的 v-if、v-show、v-for、v-model 等。

指令分为全局指令和局部指令,全局指令是注册在 Vue.directive 下,局部是放在组件的 directives: {} 对象中。

指令的钩子函数

  • bind 只调用一次,指令第一次绑定到元素时调用
    • 例如 copy 指令
  • inserted 被绑定元素插入父节点时调用
    • 例如 focus 指令
  • update 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前
  • componentUpdated 指令所在组件的 VNode 及其子 VNode 全部更新后调用
  • unbind 只调用一次,指令与元素解绑时调用
    • 例如 copy 的解绑指令

指令钩子函数会被传入以下参数:

  • el:指令所绑定的元素,可以用来直接操作 DOM
  • binding:一个对象,包含以下 property
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
    • oldValue:指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • 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:上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用。
JS
Vue.directive('demo',{
    // 当指令绑定到 HTML 元素上时触发.**只调用一次**
    bind() {
        console.log('bind triggerd')
    },
    // 当绑定了指令的这个HTML元素插入到父元素上时触发(在这里父元素是 `div#app`)**.但不保证,父元素已经插入了 DOM 文档.**
    inserted() {
        console.log('inserted triggerd')
    },
    // 所在组件的`VNode`更新时调用.
    updated() {
        console.log('updated triggerd')
    },
    // 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
    componentUpdated() {
        console.log('componentUpdated triggerd')
    },
    // 只调用一次,指令与元素解绑时调用.
    unbind() {
        console.log('unbind triggerd')
    }
})
Vue.directive('demo',{
    // 当指令绑定到 HTML 元素上时触发.**只调用一次**
    bind() {
        console.log('bind triggerd')
    },
    // 当绑定了指令的这个HTML元素插入到父元素上时触发(在这里父元素是 `div#app`)**.但不保证,父元素已经插入了 DOM 文档.**
    inserted() {
        console.log('inserted triggerd')
    },
    // 所在组件的`VNode`更新时调用.
    updated() {
        console.log('updated triggerd')
    },
    // 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
    componentUpdated() {
        console.log('componentUpdated triggerd')
    },
    // 只调用一次,指令与元素解绑时调用.
    unbind() {
        console.log('unbind triggerd')
    }
})

业务中常用的自定义指令

  • v-wave 点击水波纹效果
  • v-copy 点击复制
  • v-loading 加载中
  • v-debounce 按钮防抖
  • v-lazyload 图片懒加载
  • v-draggable dom 拖拽
  • v-auth 权限控制

实现 copy 指令

JS
// directive/Clipboard.js
import Clipboard from "clipboard"; // 三方js插件

export default {
    /**
     * el 指令所绑定的元素,除el以外参数都为只读属性
     * binding 可以设置指令信息的对象,如 value,v-copy="value"
     * vnode Vue 编译生成的虚拟节点
    */
    bind(el, binding = {}, vnode) {
        // 设置样式
        el.style.cursor = 'copy'

        // 实例化 clipboard
        const clipboard = new Clipboard(el, {
            text: () => binding.value
        })

        clipboard.on('success', e => {
            console.log("已复制到剪切板");
        })

        clipboard.on('error', e => {
            console.log("复制失败");
        })
    },
    // 需要 coply 内容更新时调用,将更新后的值绑定到 clipboard 对象上
    update(el, binding) {
        el.__clipboard__.text = () => binding.value
    },
    // 当dom被移除(比如组件销毁)时,解绑,防止内存泄漏
    unbind(el, binding) {
        el.__clipboard__.destroy();
        delete el.__clipboard__;
    }
}
// directive/Clipboard.js
import Clipboard from "clipboard"; // 三方js插件

export default {
    /**
     * el 指令所绑定的元素,除el以外参数都为只读属性
     * binding 可以设置指令信息的对象,如 value,v-copy="value"
     * vnode Vue 编译生成的虚拟节点
    */
    bind(el, binding = {}, vnode) {
        // 设置样式
        el.style.cursor = 'copy'

        // 实例化 clipboard
        const clipboard = new Clipboard(el, {
            text: () => binding.value
        })

        clipboard.on('success', e => {
            console.log("已复制到剪切板");
        })

        clipboard.on('error', e => {
            console.log("复制失败");
        })
    },
    // 需要 coply 内容更新时调用,将更新后的值绑定到 clipboard 对象上
    update(el, binding) {
        el.__clipboard__.text = () => binding.value
    },
    // 当dom被移除(比如组件销毁)时,解绑,防止内存泄漏
    unbind(el, binding) {
        el.__clipboard__.destroy();
        delete el.__clipboard__;
    }
}
JS
// directive/index.js
import Clipboard from './Clipboard'

export default {
    install (Vue) {
        Vue.directive('copy', Clipboard)
    }
}
// directive/index.js
import Clipboard from './Clipboard'

export default {
    install (Vue) {
        Vue.directive('copy', Clipboard)
    }
}
JS
// main.js
import Clipboard from "./directive/Clipboard";
Vue.use(Clipboard)
// main.js
import Clipboard from "./directive/Clipboard";
Vue.use(Clipboard)

实现权限控制指令