一、什么是指令

学习 vue 的时候必定会接触指令,那么什么是指令呢?

  • 在 vue 中提供了一些对于页面和数据更为不便的输入,这些操作就叫做指令,以 v-xxx 示意,比方 html 页面中的属性 <div v-xxx ><div>
  • 比方在 angular 中 以 ng-xxx 结尾的就叫做指令
  • 指令中封装了一些 DOM 行为,联合属性作为一个暗号,暗号有对应的值,依据不同的值,会进行相干 DOM 操作的绑定,即能够进行一些模板的操作
    • vue 中罕用的一些内置 v- 指令:
      • v-text:元素的 innerText 属性,只能用在双标签中, 和{{ }}成果是一样的,应用较少
      • v-html:元素的 innerHTML,其实就是给元素的 innerHTML 赋值
      • v-show:元素的显示与暗藏,基于 css 款式的切换。如果确定要暗藏,会给元素的 style 加上display: none
      • v-if:元素的插入和移除操作,相当于对元素的销毁和创立。如果表达式的值为 false,会留下一个 <!----> 作为标记,若将来 v-if 的值是 true 了,就在这里插入元素(如果 if 有 else 就不要独自留坑了)。
      • v-else-if:前一个相邻元素必须有 v-if 或 v-else-if
      • v-else:前一个相邻元素必须有 v-if 或 v-else-if,如果 v-if 和 v-else-if 都有对应的表达式,则 v-else 能够间接写
      • v-for:用于循环渲染一组数据(数组或对象)。必须应用特定语法:v-for="alias in expression"。注:当 v-for 和 v-if 同处于一个节点时,v-for 的优先级比 v-if 更高。即 v-if 将运行在每个 v-for循环中
      • v-on:次要用来监听 dom 工夫,而后执行一些操作。简写为【@
      • v-model:用于 inputtextarea 等表单控件上创立双向数据绑定。
      • v-bind:动静的绑定一个或多个属性,罕用于绑定 class,style,href 等。
      • v-once:组件和元素只渲染一次,当数据发生变化,也不会从新渲染。
        • v-if 和 v-show 的比照:
          • v-if 是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当的被销毁和重建。
          • v-if 也是惰性的,如果在初始渲染时条件为假,则什么也不做,直到条件第一次为真时,才会开始渲染条件块。
          • 相比之下 v-show 就简略的多,不论初始条件是什么,元素总是会被渲染,并且只是简略的基于 css 进行切换。
            • 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因而,如果须要十分频繁的切换,则应用 v-show 较好,如果在运行时条件很少扭转,则应用 v-if 较好。

              在理论的开发过程中,可能这些内置指令并不能满足所有的需要,或者说想为元素附件一些特地的性能。这时候,就须要用到 Vue 给咱们提供的一个弱小又灵便的性能「 自定义指令 」。

              官网api 文档里有这么一句话:对一般 DOM 元素进行底层操作,这时候就会用到自定义指令。也就是说自定义指令解决的问题或者说应用场景是对一般 DOM 元素进行底层操作,所以咱们不能自觉的胡乱的应用自定义指令。

              二、自定义指令的钩子函数

              Vue 提供了自定义指令的几个钩子函数:

              • bind:指令第一次绑定到元素时调用,只执行一次。在这里能够进行一次性的初始化设置。
              • inserted:被绑定的元素,插入到父节点的 DOM 中时调用(仅保障父节点存在)。
              • update:组件更新时调用。
              • componentUpdated:组件与子组件更新时调用。
              • unbind:指令与元素解绑时调用,只执行一次。
                • 留神:

                  1. 除 update 与 componentUpdated 钩子函数之外,每个钩子函数都含有 el、binding、vnode 这三个参数
                  2. 在每个函数中,第一个参数永远是 el, 示意被绑定了指令的那个 dom 元素,这个el 参数,是一个原生的 JS 对象,所以 Vue 自定义指令能够用来间接和 DOM 打交道
                  3. binding 是一个对象,它蕴含以下属性:name、value、oldValue、expression、arg、modifiers
                  4. oldVnode 只有在 update 与 componentUpdated 钩子中失效
                  5. 除了 el 之外,binding、vnode 属性都是只读的
                    1. 钩子函数说白了也就是生命周期,即当一个指令绑定到一个元素上时,这个指令外部有5个生命周期事件函数。接下来创立一个案例来看看这几个钩子函数的触发状况:

                      <p v-test>这是一段文字<p>export default {    ... ...    directives: {        test: {              bind () {                console.log('bind')              },              inserted () {                console.log('inserted')              },              update () {                console.log('update')              },              componentUpdated () {                console.log('componentUpdated')              },              unbind () {                console.log('unbind')              }        }    }}

                      后果:

                      页面渲染时,触发了 bindinserted 函数。那么另外三个钩子函数什么时候会触发呢?

                      对于 update 的官网解释:

                      update:所在组件的 VNode 更新时调用,然而可能产生在其子 VNode 更新之前。指令的值可能产生了扭转,也可能没有。然而你能够通过比拟更新前后的值来疏忽不必要的模板更新 (具体的钩子函数参数见下)。

                      有点纳闷,‘ 所在组件的 VNode ’ 是指以后绑定了该指令的 dom 元素吗?如果是的话,是不是只有以后元素的状态产生了变动就会触发 update 呢?如下通过 v-show 来切换元素显示暗藏:

                      <p v-test v-show="show">这是另外一段文字<p><button @click="show = !show">toggle<button>export default {  data () {    return {      show: true    }  }}

                      默认还是触发 bindinserted ,当点击按钮切换元素的 display 时,后果如下:

                      即:扭转元素的款式的时候触发了 updatecomponentUpdated 函数。
                      如果应用 v-if 会触发哪个事件呢?

                      <p v-test v-if="show">这是另外一段文字<p><button @click="show = !show">toggle<button>

                      后果:

                      发现 unbind 被触发,因为 v-if 是删除或者重建 dom 元素,当指令绑定的元素被销毁时,会触发指令的 unbind 事件,新建显示仍是触发 bindinserted

                      总结:

                      • bind():当指令绑定在 HTML 元素上时触发
                      • inserted():当指令绑定的元素插入到父节点中的时候触发
                      • update():当指令绑定的元素状态款式、内容(这里指元素绑定的 vue 数据) 产生扭转时触发
                      • componentUpdated():当 update() 执行结束之后触发
                      • unbind():当指令绑定的元素从 dom 中删除时触发
                        • 举几个利用场景的栗子
                          (1、输入框主动获取焦点(官网示例)。
                          (2、点击下拉菜单以外的区域暗藏菜单。
                          (3、输出的邮箱、电话的校验。

                          下面这几个场合,在做我的项目的时候能够用其余办法代替,然而 vue 自定义指令能做到一处定义,全局调用,使得代码简洁高效,更便于保护。

                          指令的注册形式和「过滤器」「混入」「组件」注册的形式一样都分为两种:一是全局注册,二是部分注册。

                          三、全局指令

                           给元素增加随机背景<div v-bgcolor><div>   Vue.directive('bgcolor', {    bind: function(el, binding, vnode) {        el.style.backgroundColor = "#" + Math.random().toString(16).slice(2,8);    }})

                          留神:在定义的时候,指令的名称后面不须要加 v- 前缀,在调用的时候,必须在指定的名称前加上 v-前缀来进行调用

                          四、部分指令

                           和data, methods同级methods: {},directives: {    bgcolor: {         bind: function(el, binding) {            el.style.backgroundColor = "#" + Math.random().toString(16).slice(2,8);        }    }}

                          我集体更偏向于应用全局注册的形式,因为既然曾经应用了自定义指令,应该是通用的可复用的。所以提供整个我的项目应用的指令才更有价值,而不仅仅只限于某个组件外部。如果繁多中央应用间接把性能搂进去就行了,何必费这力量。

                          五、带参数的自定义指令

                          <div v-bgcolor='{color: 'orange'}'><div>Vue.directive('bgcolor', {    bind: function(el, binding) {        el.style.backgroundColor = binding.value.color;    }})

                          六、函数简写

                          如果想在 bind 和 update 时触发雷同行为,而不关怀其它的钩子,能够这样写:

                           全局Vue.directive('bgcolor', function (el, binding) {      el.style.backgroundColor = binding.value}) 部分directives: {    bgcolor: (el, binding) => {        el.style.backgroundColor = binding.value      }}

                          七、利用实例

                          相熟指令的创立形式与参数之后,咱们就用它来创立两个理论案例。

                          1.通过指令来实现点击空白处子菜单暗藏的性能,具体代码如下:

                           clickOutside.jsexport default {    bind (el, binding) {        const self = {}  定义一个公有变量,不便在unbind中能够解除事件监听        self.documentHandler = (e) => {            if (el.contains(e.target)) {  这里判断绑定的元素是否蕴含点击元素,如果蕴含则返回                return false            }            if (binding.value) {  判断指令中是否绑定了值                binding.value(e)  如果绑定了函数则调用那个函数,此处 binding.value就是handleClose办法            }            return true        }        document.addEventListener('click', self.documentHandler)    },    unbind (el) {         解除事件监听        document.removeEventListener('click', self.documentHandler)        delete self.documentHandler    }}

                          在组件中应用:

                          <template>    <div>        <div v-show="isShow" v-clickoutside="handleClickOutside" @click="showOrHide">            子菜单 ...         <div>    <div><template><script>    import clickoutside from '.jsclickOutside'        export default {        ... ...        directives: {            clickoutside        },        data() {            return {                isShow: true,            };        },        methods: {            handleOutsideClick () {                this.isShow = false            }        }    }<script>

                          2.自定义指令来优化图片的加载:图片在加载过程中,未加载实现时应用灰色背景占位,图片加载完后间接显示

                          <template>    <div>        <!-- 参数不能够间接填写url地址-->        <img v-imgUrl='url' >     <div><template><script>    export default {        data () {            return {                url: '..srcassetslogo.png'            }        }    }<script> 全局注册Vue.directive('imgUrl', function (el, binding) {    el.style.backgroundColor = '#FEFEFE' 设置背景色彩    var img = new Image()    img.src = binding.value  binding.value 指令后的参数    img.onload = function () {        el.style.backgroundColor = ''        el.src = binding.value    }})