Vue2.x指令

  • 指令(Directives),指带有v-前缀的特殊属性。

  • 当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM,是Vue双向绑定最基础的表现。

内置指令

  • v-text

    <div v-text="text"></div>

    绑定的参数与将作为元素内部的textContent,等价于

    <div>{{text}}</div>
  • v-html

    <div v-html="html"></div>

    绑定的参数将作为元素的innerHTML内容,要注意防止xss攻击

  • v-bind

    <div v-bind:class="className"></div>

    Vue中最基本的参数双向绑定,当用于原生的元素标签时,可以将参数绑定至标签的原生属性上,当用于封装的组件时,将作为props传入组件内。通常会使用以下的写法

    <div :class="className"></div>
  • v-on

    <button v-on:click="handleClick(args, $event)">click me!</button>

    用于绑定事件,事件方法定义在methods内。对于有原生事件的标签来说,v-on能够直接支持。而对于封装的组件而言,可以在组件内使用$emit()来定义事件触发的条件。入参参数在没必要的情况下能够省略。通常会使用以下写法

    <button @click="handleClick(args, $event)"></button>
    • 事件修饰符:

    <!-- 使用方法 -->
    <button v-on:click.stop="handleClick">click me!</button>

    .stop: 阻止冒泡,调用event.stopPropagation()

    .prevent: 阻止默认事件,调用event.preventDefault(),如用于表单提交事件

    .capture: 添加事件侦听器时使用事件捕获模式,即元素自身触发的事件先在事件方法内处理,然后才交由内部元素进行处理

    .self: 只当事件在该元素本身(比如不是子元素)触发时触发回调

    .once: 事件只触发一次

    .passive: 用于滚动事件,滚动事件的默认行为 (即滚动行为) 将会立即触发

  • v-model

    <input v-model="inputValue">

    元素双向绑定的数据,与v-bind类似,相比于前者,在组件封装中,使用v-model绑定的数据更偏向于组件的核心数据,如表单绑定的数据,输入框内的内容等。

    注意v-model前不要加 : ,否则其实际意义将会变成v-bind:v-model,与一个普通的props无异。

    在组件内部进行接收或者监听时,都使用value。另外,由于prop本身的单向传输性,当组件内部数据更新且需要返回给外部时,得使用$emit('input', value),以下为一个简单的v-model在组件内外双向绑定的写法

    export default {
      data() {
        return {
          innerValue: '',
        }
      }
      props: {
        value: [String, Number]
      },
      watch: {
        value(newVal) {
          this.innerValue = newVal;
        },
        innerValue(newVal) {
          this.$emit('input', newVal);
        }
      }
    }
  • v-for

    <div v-for="item in items" :key="item">{{item.content}}</div>
    export default {
      data() {
        return {
          items: [1,2,3]
        }
      }
    }

    操作dom的Vue指令,通过遍历一个数组来达到重复渲染当前元素的效果,如上述代码的实际渲染效果为

    <div>1</div>
    <div>2</div>
    <div>3</div>

    在Vue2.x中,要注意想要触发dom的变化,就需要触发监听数组变化的钩子,而当数组内对象层级过深时,钩子将不会触发,于是会导致model层更新,而view层没有响应的情况,此时可以使用$forceUpdate强制触发钩子。

    v-for的key属性,可以理解为一个主键,可用于提升dom重载时的性能。

  • v-if与v-show

    <div v-if="isDicShow">1</div>
    <span v-show="isSpanShow">2</span>

    v-if相伴的还有v-else-ifv-else,将作为v-if的一类一起讨论。

    v-ifv-show都通过赋值其的表达式的真假来控制所在元素的是否显示。两者的区别在于v-if绑定的表达式的真假性变化时,会导致元素的渲染或者销毁。而v-show仅仅是控制元素的display属性是否为none,绑定值为false时,我们依然可以通过审查元素找到该元素。关于两者的区别,其实是个老生常谈的问题,本质上,还是一个考虑性能的问题。

    • v-if无初始渲染消耗,但有较高的切换消耗,v-show则相反。

    • 两者的使用要根据实际业务场景进行考量,对首次打开性能要求较高的界面,可以考虑使用v-if,对于需要频繁切换的元素,则可以考虑使用v-show

  • v-cloak

    <div class="demo-class" v-cloak>{{msg}}</div>
    [v-cloak] {
      display: none;
    }

在开启禁止浏览器缓存或者网络比较慢的时候,即vue.js 加载较慢的时候,由于Vue实例并没有编译完成,所以对于类似 {{msg}}Mustache 标签会被直接展示出来。只有当 Vue 编译加载完成后,参数的真正内容才会被展示出来。这就导致了界面渲染时会有一小段时间的闪动问题。

v-cloak 主要就是用于优化这个用户体验的问题,用CSS选择器来操作拥有该指令的样式,设置其为 display:none ,那么在vue.js加载期间,该元素就不会被展示出来,直到 Vue 实例加载完毕。

事实上 v-cloak 指令在实际编码过程中,用到的机会还是比较少的。在较为大型、工程化的项目当中,都会使用 vue-router 实现路由挂载,所以在非首页加载的情况下,Vue实例都早已加载完成,此时就不再有使用该指令的必要。

  • v-pre

    <div v-pre>{{msg}}</div>

拥有 v-pre 指令的元素与其子元素会直接跳过 Vue 的编译过程,当作普通的dom进行渲染。跳过编译过程一来可用于在必要的时候展示 {{msg}} 这类 Mustache 标签。二来可用于缩短一些不含需要编译内容的dom的加载时间,从而提高整个界面的加载效率。从实际使用情况来说,对性能的提升还是较为有限的,不过可以作为界面性能优化的一个方面加以实施。

  • v-once

    <div v-once>{{msg}}</div>

同样是一个用于提高界面性能的指令,可以从字面意思来理解,使用v-once指令的元素只会被编译一次,也就是说类似于{{msg}}的标签内的参数会被正确展示出来,但有且仅有这一次渲染,若界面出现重新渲染,该元素就不再会进行编译,只会展示第一次编译的内容。该指令一般用于有需要编译的Vue语法,但其依旧为静态内容,所以仅需编译一次,可以与v-pre相区分。

自定义指令

Vue除去以上内置指令外,还可以让开发人员根据生产需要开发自定义指令。通过对内置指令的介绍,很容易可以认识到,指令的作用其实主要用于对于DOM元素的操作上。比如官方文档里给的一个例子,就是用于做输入框获取焦点的。

自定义指令与Vue-components类似,可以进行全局挂载。比如获取输入框焦点这类比较常见的交互场景,就可以作为一个全局的自定义指令进行挂载。

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

同样的,也可以仅在某个界面内进行局部挂载。

new Vue({
  el: "#app",
  directives: {
    focus: {
      inserted: function(el){
        el.focus();
      }
    }
  }
})

对于指令功能的实现,与Vue实例类似,都具有一个完整的生命周期及其对应的钩子函数,指令的生命周期整体如下。

bind => inserted => update => componentUpdated => unbind

对于生命周期的具体解释,以及钩子函数各个入参的含义,官方文档都已经给出了很明朗的解释,就不赘述。

另外,对于官方文档中提及的动态参数指令 v-mydirective:[argument]="value",即可以在指令上绑定一个[arguement]来作为组件实例更新的一个入参,由于入参是一个动态的参数,所以可使指令的定义更加灵活。以下例子中的dir就是一个传入的入参,对应于指令方法中的arg

<div v-pin:[dir]="200"></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'
  }
})

而其实指令等号后面的部分同样也可以作为一个动态的参数传入,所以当等号后面部分的参数更新时,在update钩子内进行更新,同样也可以实现动态参数指令的效果。

最后更新于