全栈-Vue-directive

1,120 阅读1分钟

本章主要介绍 Vue 中direction 的一些实际应用场景

指令与自定义指令是什么

  • Vue 中指令是 是一种特殊的用在 模板语法中的 属性 (attribute)

  • Vue 中有官方自己定义的 指令(v-if v-on 等),后面跟随js表达式

  • Vue 也提供给用户 自己定义自己的 指令,那就可大有作为了

自定义指令内部api解析

el, binding, vnode 这几个元素拿到,就可以搞很多黑科技,骚操作

可以自行打印里面都包含哪些有用的信息

  • el 中信息

     el可以获取当前dom节点,并且进行编译,也可以操作事件
     el.style.border="1px solid red";  //操作style所有样式
     console.log(el.value);  //获取v-model的值
     console.log(el.dataset.name) //data-name绑定的值,需要el.dataset来获取
    
  • vnode中信息

    console.log(vnode.context.$route); //获取当前路由信息,根据路由信息,可以控制改DOM是否显示 route.meta 角色信息
    当然,想的更远些 vnode.context 还可以拿到 很多 Vue的信息
    
  • 生命周期 一般用update多

// 注册
Vue.directive('my-directive', {
  // 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
  bind: function (el, binding, vnode) {
    // 重点:拿到下面几个元素,基本就
  	// el : 当前挂载指令的DOM元素
  	// binding: 一个对象,包含该指令的很多信息
  	// vnode:当前挂载指令的 虚拟DOM结构 
  },
  // 被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
  inserted: function () {},
  // 一般都在此处 做很多逻辑处理,因为会 调用很多次
  // 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改		变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数		见下)。
  update: function () {},
    // 指令所在组件的 VNode 及其子 VNode 全部更新后调用
  componentUpdated: function () {},
  //只调用一次,指令与元素解绑时调用
  unbind: function () {}
})

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

实战中的场景

  • v-loading 全局加载

     Vue.directive('loading', {
            update(el, binding, vnode) {
              if (binding.value) {
                const div = document.createElement('div')
                div.innerText = '加载中...'
                div.setAttribute('id', 'loading')
                div.style.position = 'absolute'
                div.style.left = 0
                div.style.top = 0
                div.style.width = '100%'
                div.style.height = '100%'
                div.style.display = 'flex'
                div.style.justifyContent = 'center'
                div.style.alignItems = 'center'
                div.style.color = 'white'
                div.style.background = 'rgba(0, 0, 0, .7)'
                document.body.append(div)
              } else {
                document.body.removeChild(document.getElementById('loading'))
              }
            }
          })
    
  • 根据路由角色控制DOM(一般是按钮多)是否显示

     bind: function (el, binding, vnode) {
      // 获取按钮权限  路由中 meta 中的角色
      let btnPermissions = vnode.context.$route.meta.btnPermissions.split(",");
      if (btnPermissions.indexOf('admin')<0) {
      	// 不是admin 就不显示
      	// 当然此处也可以 将 el 样式隐藏也行
       el.parentNode.removeChild(el);
      }
     }
    
  • 根据后台下发 权限 字段,控制当前DOM是否展示

     // 很多时候,服务器下发了  showBtn 字段就代表 显示某个 按钮,前端一般把控制权限的数据都放在内存中
     // 这样写 在 bind update 都会执行
    Vue.directive('check-permission', function (el, binding) {
      var success = checkPermission(binding.value); // 拿到绑定的值
      if(!success){
        el.style.display = 'none';
      }
    })
    
    function checkPermission(permissionKey) {
      var values = localStorage.getItem("userPermissions");
      if (!values) {
        console.log('can not find permissions config from localstorage, function access will be denied.');
        return false;
      }
      var ret = values.split(',').find(item => item === permissionKey) != null;
      console.log('===========check permission, key:' + permissionKey + ", result:" + ret + "==========");
      return ret;
    }
    
    // 使用
    v-check-permission="'showBtn'"