Vue源码 指令(五)

428 阅读2分钟

Vue中的指令分为内置指令和自定义指令。

内置指令

比如 v-if、v-show、v-for、v-on、v-bind

它们的实现方式是各不相同的,因为它们的能力更加复杂,所以需要底层的算法支持,自定义指令是做不到的。

v-if

在模版编译代码生成阶段生成应该渲染的代码

<li v-if="show">{{show}}</li>
<li v-else>{{show}}</li>

代码字符串:show ? _c('li',[_s(show)]):_c('li',[_s(show)])
v-if只渲染为true 模版

v-show 是通过设置css 属性 display:none 控制的,所以dom元素是渲染出来的。

v-for

在模版编译代码生成阶段生成应该渲染的代码

<li v-for='item in list'>{{item}}</li>

代码字符串:_l = renderList
_l((list),function(item){
  return _c('li',[_v('v-for' + _s(item))])
})

v-on

用于绑定事件,核心原理就是通过 addEventListent 绑定方法

自定义指令

是通过 Vue.directive去添加的,它的原理是挺简单的,就是添加执行的方法。

Vue.directive

指令是传对象的话,是一个直接赋值的操作,如果是函数的话,会将函数赋值给 bindupdate

// 注册
Vue.directive('my-directive', {
  bind: function () {},
  inserted: function () {},
  update: function () {},
  componentUpdated: function () {},
  unbind: function () {}
})

// 注册 (指令函数)
Vue.directive('my-directive', function () {
  // 这里将会被 `bind` 和 `update` 调用
})


// 这是我项目中使用控制权限的指令
Vue.directive('permission', {
  inserted(el, bind, vnode) {
    // 当前绑定的dom元素
    console.log(el, 'el') 
    // 绑定的参数:expression、v-permission
    console.log(bind, 'bind') 
    // VNode:这里可以通过 context 可以访问到当前组件的参数
    console.log(vnode, 'vnode')
    const { value } = bind
    // 获取存在Vuex中的权限
    const roles = store.getters.func_permissions
    if (value && value instanceof Array && value.length > 0) {
      const permissionRoles = value
      const hasPermission = roles.some((role) => {
        return permissionRoles.includes(role)
      })
      // 如果没有权限的话,就把当前孩子remove
      if (!hasPermission) {
        el.parentNode && el.parentNode.removeChild(el)
      }
    } else {
      throw new Error(`need roles! Like v-permission="['admin','editor']"`)
    }
  },
})

自定义指令例子如下。

<!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>Vue指令</title></title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.js"></script>

  </head>
  <body>
    <div id="app">
      <input type="text" v-model="inputValue" v-focus="1" />
    </div>
    <script>
      Vue.directive('focus', {
        // 第一次绑定元素时调用
        bind(el, bind, vnode) {
          console.log('bind')
        },
        // 当被绑定的元素插入到 DOM 中时……
        inserted: function(el) {
          console.log('inserted')
          el.focus()
        },
        // 所在组件VNode发生更新时调用
        update() {
          console.log('update')
        },
        // 指令所在组件的 VNode 及其子 VNode 全部更新后调用
        componentUpdated() {
          console.log('componentUpdated')
        },
        // 只调用一次,指令与元素解绑时调用
        unbind() {
          console.log('unbind')
        }
      })
      new Vue({
        data: {
          inputValue: ''
        }
      }).$mount('#app')
    </script>
  </body>
</html>

各位看官如遇上不理解的地方,或者我文章有不足、错误的地方,欢迎在评论区指出,感谢阅读。