vue自定义指令使用与使用场景解读

关于自定义指令,事实上在做前端开发第一年时根本就没有任何的了解,第一次接触到这个概念还是在一次面试当中,我讲了一堆如何遍历标签的属性的原生方法,结果面试官直接回答:这不是vue自定义指令吗。。。233

嗯 那么开始进入主题。

1.自定义指令的解释

vue功能默认内置的指令 (v-model ,v-show ,v-for 等等…)
那么自定义指令就是自己设置一个指令,比如聚焦。
// 注册一个全局自定义指令 v-focus

//全局注册
Vue.directive('focus', {
	  // 当被绑定的元素插入到 DOM 中时……
	  inserted: function (el) {
	    // 聚焦元素
	    el.focus()
	  }
	})
//组件注册
//如果想注册局部指令,组件中也接受一个 directives 的选项:
directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus()
    }
  }
}
//使用方式
<input v-focus>

到此,基本上我们就知道自定义指令的用法和作用了,但是我们不仅会有疑问,这个功能的使用场景在哪?那么带着这个问题我回想起面试时我也问过面试官这个问题,面试官回答:在使用组件时,你想对组件使用v-model咋办?
嗯…
面对这个问题,有两种解决方式,
一种从prototype原型链去复刻vue v-model的原理加在组件上。
而另一种便是使用自定义指令。
那么我们来尝试自定义指令的v-model效果吧。

先新建一个组件zidingyizujian.vue(注意:这里因为偷懒所以用拼音命名,实际开发不要用拼音!)

<template>
  <div class="zi-ding-yi-zujian">
      我是个很牛的input
      <input  type="text" v-model="value">
  </div>
</template>

<script>
export default {
    data(){
        return{
            value:'很牛的v-model'
        }
    }
}
</script>

再建一个页面zidingyi.vue调用组件

<template>
  <div class="zi-ding-yi">
      自定义组件测试
      <zidingyizujian></zidingyizujian>
  </div>
</template>

<script>
import zidingyizujian from './zidingyizujian.vue'
export default {
    components:{
        zidingyizujian
    }
}
</script>

效果:在这里插入图片描述

ok, 我的想法是新增一个comModel指令控制组件里面的input的v-model。
vue自定义指令使用与使用场景解读_第1张图片

那么开始搞起!

在组件zidingyizujian.vue

export default {
    data(){
        return{
            value:'很牛的v-model'
        }
    },
    directives: {
        model: {
            // 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
            bind:function(){

            },
            //被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
            inserted: function (el,binding,vnode,oldVnode) {
                console.log('inserted,','el:',el,'binding:',binding,'vnode:',vnode,'oldVnode:',oldVnode)
            },
            //所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。
            //但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
            update:function(){

            },
            //指令所在组件的 VNode 及其子 VNode 全部更新后调用。
            componentUpdated:function(){

            },
            //只调用一次,指令与元素解绑时调用。
            unbind:function(){

            }
        }
    }
}

得到下面的输出:
在这里插入图片描述
我们来看看每个参数是什么意思:

1.el
就是那个组件的dom
在这里插入图片描述

2.binding
vue自定义指令使用与使用场景解读_第2张图片
name:指令名,不包括 v- 前缀。
value:指令的绑定值,例如:v-my-directive=“1 + 1” 中,绑定值为 2。
expression:字符串形式的指令表达式。例如 v-my-directive=“1 + 1” 中,表达式为 “1 + 1”

3.vnode 虚拟dom
vue自定义指令使用与使用场景解读_第3张图片
虚拟dom的字段比较多,我们着重看context这个属性,有想了解更多的朋友可以看官方文档的vue虚拟节点文章:https://cn.vuejs.org/v2/api/#VNode-%E6%8E%A5%E5%8F%A3

看完参数后我们就要理一理逻辑了

简单来讲,分为两步,1.set,2.get.(双向绑定的核心)
那么第一步set:
通过el节点获取它的子节点input。监听input输入,将input输入的值传给页面绑定pageValue。 这里就要用到虚拟节点vnode和指令属性binding来获取:vnode.context[binding.expression]

第二步get:
通过钩子函数update:function(){} 实时监听当前指令绑定的页面的值变化。然后更新到子组件。

思路有了,接下来就是代码:

export default {
    components:{
        zidingyizujian,
    },
    data(){
        return{
            pageValue:'这是页面的v-model'
        }
    },
    created(){
    },
    directives: {
        'comModel': {
            // 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
            bind:function(el,binding,vnode,oldVnode){
            },
            //被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
            inserted: function (el,binding,vnode,oldVnode) {
                console.log(el,'el')
                console.log(binding,'binding')
                console.log(vnode,'vnode')
                console.log(oldVnode,'oldVnode')
                let input = el.getElementsByTagName('input')[0];
                input.oninput = e => {
                    let value = e.target.value;
                    vnode.context[binding.expression] = value;
                }
            },
            //所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。
            //但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
            update:function(el,binding,vnode,oldVnode){
                let input = el.getElementsByTagName('input')[0];
                input.value = binding.value;
            },
            //指令所在组件的 VNode 及其子 VNode 全部更新后调用。
            componentUpdated:function(){

            },
            //只调用一次,指令与元素解绑时调用。
            unbind:function(){

            }
        }
    }
}

你可能感兴趣的:(vue)