自定义指令中的钩子函数

一个指令定义对象可以提供如下几个钩子函数 (均为可选):

  • 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 钩子中可用。

应用示例

1. 自动获取焦点 v-focus

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

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

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

然后可以在模板中任何元素上使用新的 v-focus property,如下:

<input v-focus>

2. 自定义指令之动态参数 v-change-font

// 实现动态传值的指令(一)——<script>内使用驼峰,<body>内短横线加小写
    Vue.directive('changeFont',{
        bind:function(el, binding){
            el.style.color = binding.value
            el.style.fontSize = '20px'; // 样式也要使用驼峰
            el.style.fontFamily = 'Microsoft YaHei'; // 样式也要使用驼峰
            console.log(binding.value)
        }
    })

此指令可以更改绑定元素的字体、大小,以及动态更改颜色:

<input v-change-font="'orange'" type="text"/>

3.动态参数+函数简写 = v-fix 固定定位

// 实现动态传值的指令(二)
    Vue.directive('fix',function (el, binding, vnode) { // 函数简写
            el.style.position = 'fixed'
            var s = binding.argument
            el.style[s] = binding.value + 'px'
        }
    )

此指令可以实现绑定元素的固定定位,动态接收参数固定位置top/left及px

<div style="height:100px">
	<p>Scroll dawn the page</p>
	<p v-fix:[direction]='20'>Stick me 200px from the top of this page</p>
</div>

4. 用了各种钩子函数参数的自定义指令 v-demo

Vue.directive('demo',{
        bind:function(el, binding, vnode){
            var s = JSON.stringify;
            console.log(binding)
            console.log(vnode)
            el.innerHTML = 
                '自定义指令名称-name:   ' + s(binding.name) + '<br>' + 
                '自定义指令传的参数值-value:    ' + s(binding.value) + '<br>' + 
                '自定义指令传的参数值-expression:  ' + s(binding.expression) + '<br>' + 
                '属性-argument: ' + s(binding.argument) + '<br>' + 
                '包含修饰符的对象-modifiers: ' + s(binding.modifiers) + '<br>' + 
                '虚拟节点-vnode keys:  ' + Object.keys(vnode).join(', ')

        }
    })

这个指令主要为了打印看一下各种钩子函数参数:

<!-- 字符串形式参数——记得要加单引号否则报错 -->
<div v-demo:foo.a.b="'1+1'"></div><hr>
            
<!-- 表达式形式参数——表达式不用加单引号 -->
<div v-demo:foo.a.b="1+1"></div><hr>

效果:

在钩子函数create中使用data中的数据 inserted钩子函数_Vue


附上全部代码,可以自己调调试试:

在钩子函数create中使用data中的数据 inserted钩子函数_javascript_02

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style type="text/css">
        .bgcolor{
            background: #c5c551;
            padding: 20px;
            width: 100%;
            height: 400px;
            display: flex;
            flex-direction:column;
            justify-content: center;
            align-items: center;
            overflow: scroll;
            padding: 150px 35px;
        }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" type="text/javascript" charset="UTF-8"></script>
</head>
<body>
    <template id="example">
        <div>
            <!-- v-focus、动态指令参数v-change-font -->
            <div>
                <input v-focus v-change-font="'orange'" type="text" v-model="multiplierA" />
                <input type="text" v-model="multiplierB">
                <button @click="result = multiplierA*multiplierB">The anwser is {{ result }}</button>
            </div><hr>

            <!-- 动态指令参数v-fix——固定定位 -->
            <div style="height:100px">
                <p>Scroll dawn the page</p>
                <p v-fix:[direction]='20'>Stick me 200px from the top of this page</p>
            </div><hr>
            
            <!-- 字符串形式参数——记得要加单引号否则报错 -->
            <div v-demo:foo.a.b="'1+1'"></div><hr>
            
            <!-- 表达式形式参数——表达式不用加单引号 -->
            <div v-demo:foo.a.b="1+1"></div><hr>
        </div>
    </template>
    <div class="bgcolor" id="app">
        <div>
            <do-example></do-example>
        </div>
    </div>
</body>
<script type="text/javascript">
    Vue.component("doExample",{
        data:function(){
            return{
                multiplierA: 0,
                multiplierB: 0,
                result: 0,
                direction: 'right'
            }
        },
        // 局部指令
        directives:{
            focus2:{
                inserted: function(el){
                    el.focus();
                }
            }
        },
        template: "#example"
    })

    // 全局指令
    Vue.directive('focus',{
        inserted:function(el){
            el.focus();
        }
    })

    // 实现动态传值的指令(一)——<script>内使用驼峰,<body>内短横线加小写
    Vue.directive('changeFont',{
        bind:function(el, binding){
            el.style.color = binding.value
            el.style.fontSize = '20px'; // 样式也要使用驼峰
            el.style.fontFamily = 'Microsoft YaHei'; // 样式也要使用驼峰
            console.log(binding.value)
        },
        inserted:function(el){}
    })

    // 实现动态传值的指令(二)
    Vue.directive('fix',function (el, binding, vnode) { // 函数简写
            el.style.position = 'fixed'
            var s = binding.argument
            el.style[s] = binding.value + 'px'
        }
    )

    // 用了各种钩子函数参数的自定义指令
    Vue.directive('demo',{
        bind:function(el, binding, vnode){
            var s = JSON.stringify;
            console.log(binding)
            console.log(vnode)
            el.innerHTML = 
                '自定义指令名称-name:   ' + s(binding.name) + '<br>' + 
                '自定义指令传的参数值-value:    ' + s(binding.value) + '<br>' + 
                '自定义指令传的参数值-expression:  ' + s(binding.expression) + '<br>' + 
                '暂时不存在的属性-argument: ' + s(binding.argument) + '<br>' + 
                '包含修饰符的对象-modifiers: ' + s(binding.modifiers) + '<br>' + 
                '虚拟节点-vnode keys:  ' + Object.keys(vnode).join(', ')

        }
    })

    var vm = new Vue({
        el: '#app',
        // 数据
        data:{}
    });
</script>
</html>