• Vue自定义指令


    Vue中除框架默认自带的 v-model v-show 等指令外,也允许自定义指令。需要注意的是代码的抽象和复用主要形式是"组件",确实需要对DOM元素底层进行操作时,才推荐使用指令。

    Vue中存在两种指令形式:全局指令、局部指令。

    全局指令

    直接将指令定义在 Vue 实例上

    Vue.directive('focus', function(el, binding) {
      el.focus();
    })
    
    • 1
    • 2
    • 3

    在项目中大部分情况下不会使用这种情况的全局指令,而是通过将指令单独提出来,再统一注册的方式创建全局指令。

    vue-cli 中,创建文件夹 directive,创建 index.js 文件

    // directive > index.js
    import Vue from "vue";
    import focus from "./focus";
    import color from "./color";
    
    const direvtives = {
      focus,
      color,
    }
    
    Object.keys(direvtives).forEach(item => {
      Vue.directive(key, direvtives[key]);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在main.js中引入并调用

    // main.js
    import directive from "@/directive";
    Vue.use(directive);
    
    • 1
    • 2
    • 3

    局部指令

    局部指令是指注册在组件内部,由此组件独占的指令。不推荐使用此种方案,需要用到组件的场景大部分都是需要全局注册的。

    <div v-color>div>
    
    • 1
    export default {
      name: 'a-color',
      directive: {
        focus: {
          inserted(el) {
            el.focus();
          }
        }
      },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    钩子函数

    指令中存在一系列的钩子函数:

    directive: {
      dire: {
        focus: {
          /**
           * 指令第一次绑定到元素时调用,只调用一次,一般用于初始化设置
           * */
          bind(el, binding, vNode) {
            console.log(el);  // 指令绑定的元素  
            console.log(binding.name);  // 指令名 focus
            console.log(binding.value);  // 指令绑定值 2
            console.log(binding.expression);  // 指令表达式 1 + 1
            console.log(binding.arg);  // 传给指令的参数 foo
            console.log(binding.modifiers);  // 包含修饰符的对象 {bar: true}
            console.log(vNode);  // 虚拟DOM节点 vNode {tag: 'input'...}
          },
          
          /**
           * 被绑定元素插入父节点时调用
           * */
          inserted(el, binding, vNode) {},
          
          /**
           * 所在组件虚拟DOM节点更新时调用,但是可能发生在其子vNode更新之前。
           * */
          update(el, binding, vNode, oldVnode){
            console.log(binding.oldValue);  // 指令绑定的前一个值
            console.log(oldVnode);  // 上一个虚拟DOM节点
          },
          
          /**
           * 指令所在组件的VNode及子VNode全部更新后调用
           * */
          componentUpdated(el, binding, vNode, oldVnode) {},
          
          /**
           * 指令与元素解绑时调用
           * */
          unbind(){}
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    一般而言,大部分的指令操作都在 inserted 方法中进行。另外如果想在 bind 和 update 中触发相同的行为,可以直接省略钩子函数调用,采用简写的方式。

    directive: {
      focus(el, binding) {
        el.style.color = binding.value;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    动态指令参数

    vue允许指令的参数是动态的, v-color:[args]=“value”

    <div v-color[foo]="red">div>
    
    • 1

    常用指令示例

    v-copy 一键复制文本

    copy

    <textarea v-model="copyText">textarea>
    <button v-copy="copyText">复制button>
    
    • 1
    • 2
    directives: {
      copy: {
        bind(el, { value }) {
          el.$value = value
          el.handler = () => {
            if (!el.$value) {
              alert('无复制内容')
              return
            }
            // 动态创建 textarea 标签
            const textarea = document.createElement('textarea')
            // 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域
            textarea.readOnly = 'readonly'
            textarea.style.position = 'absolute'
            textarea.style.left = '-9999px'
            // 将要 copy 的值赋给 textarea 标签的 value 属性
            textarea.value = el.$value
            // 将 textarea 插入到 body 中
            document.body.appendChild(textarea)
            // 选中值并复制
            textarea.select()
            const result = document.execCommand('Copy')
            if (result) {
              alert('复制成功') // 可根据项目UI仔细设计
            }
            document.body.removeChild(textarea)
          }
          // 绑定点击事件,就是所谓的一键 copy 啦
          el.addEventListener('click', el.handler)
        },
        // 当传进来的值更新的时候触发
        componentUpdated(el, { value }) {
          el.$value = value
        },
        // 指令与元素解绑的时候,移除事件绑定
        unbind(el) {
          el.removeEventListener('click', el.handler)
        },
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
  • 相关阅读:
    常用中间件分类
    鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Button)
    5分钟搞懂分布式可观测性
    盒子阴影和文本阴影
    Java核心编程(21)
    3D模型格式转换工具HOOPS Exchange:如何将3D PDF转换为STEP格式?
    带头双向循环链表的基本操作(c语言实现)
    深入理解 Spring MVC 的工作原理
    Spring扩展接口(4):InstantiationAwareBeanPostProcessor
    Git学习笔记2
  • 原文地址:https://blog.csdn.net/Feng_ye__/article/details/126604587