• Vue3.0 如何写自定义指令


    背景

    问:什么是指令?

    答:指令就是DOM与逻辑行为的媒介,本质就是DOM绑定的独立逻辑行为函数。除了核心功能默认内置的指令 (例如 v-model 和 v-show ),Vue 也允许注册自定义指令。Vue自定义指令和组件一样存在着全局注册和局部注册两种方式。先来看看注册全局指令的方式,通过 Vue.directive( id, [definition] ) 方式注册全局指令,第一个参数为自定义指令名称(指令名称不需要加 v- 前缀,默认是自动加上前缀的,使用指令的时候一定要加上前缀),第二个参数可以是对象数据,也可以是一个指令函数。

    在 Vue 中,代码复用和抽象的主要形式是组件。本文介绍的就是Vue3.0之后我们该如何应用这指令呢。

    Vue3.0钩子函数

    01

    **created:**在绑定元素的 attribute 或事件监听器被应用之前调用。在指令需要附加需要在普通的 v-on 事件监听器前调用的事件监听器时,这很有用

    02

    **beforeMount:**当指令第一次绑定到元素并且在挂载父组件之前调用

    03

    **mounted:**在绑定元素的父组件被挂载后调用

    04

    **beforeUpdate:**在更新包含组件的 VNode 之前调用

    05

    **pdated:**在包含组件的 VNode 及其子组件的 VNode 更新后调用

    06

    **beforeUnmount:**在卸载绑定元素的父组件之前调用

    07

    **unmounted:**当指令与元素解除绑定且父组件已卸载时,只调用一次

    目标

    抛开技术领域的探索,对于项目,我们要达成的目标是什么呢?

    试想,有这样的一些需求:

    ①. 一个最简单的表单中,需要用户对某些内容复制,比方说版本号及一些订单编号及个人信息。

    **②. **用户点击其他位置需要将此弹窗隐藏。

    ③. 自定聚焦到表单处。

    ④. 防止按钮在短时间内被多次点击,使用防抖函数限制规定时间内只能点击一次。

    实现

    import Directives from "@/Directives/index";// 自定义指令(@ 代表src)
    const app = createApp(App);
    app.use(Directives);
    app.mount("#app");
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1. index.js内容 copy为例
    import copy from "./copy"; // 引入需要的指令
    import clickoutside from "./clickoutside";
    import focus from "./focus";
    import debounce from "./debounce"
    
    const directivesList = {
      copy, // 挂载
      clickoutside,
    };
    
    const directives = {
      install: function (app) {
        Object.keys(directivesList).forEach((key) => {
          app.directive(key, directivesList[key]); // 注册
        });
      }
    };
    
    export default directives;// 抛出
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    import { ElMessage } from "element-plus";  //复制
    const copy = {
      mounted (el, { value }) {
        el.$value = value;
        el.handler = () => {
          if (!el.$value) {
            // 值为空的时候,给出提示
            ElMessage.warning({
              message: "您好,复制的值不能为空。",
              type: "warning"
            });
            return;
          }
          if (window.clipboardData) {
            window.clipboardData.setData("text", el.$value);
          } else {
            (function (content) {
              document.oncopy = function (e) {
                e.clipboardData.setData("text", content);
                e.preventDefault();
                document.oncopy = null;
              };
            })(el.$value);
            document.execCommand("Copy");
          }
    
          ElMessage.success("复制成功");
        };
        // 绑定点击事件
        el.addEventListener("click", el.handler);
      },
      beforeUpdate (el, {
        value
      }) {
        el.$value = value;
      },
      unmounted (el) {
        el.removeEventListener("click", el.handler);
      }
    };
    
    export default copy;
    
    
    • 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
    • 41
    • 42
    • 43
    const clickoutside = {
      // 初始化指令
      beforeMount (el, binding, vnode) {
        function documentHandler (e) {
        //   // 这里判断点击的元素是否是本身,是本身,则返回
          if (el.contains(e.target)) {
            return false;
          }
          //   // 判断指令中是否绑定了函数
          if (binding.value.name) {
            // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法
            binding.value(e);
          }
        }
        // // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
        el.__vueClickOutside__ = documentHandler;
        document.addEventListener("click", documentHandler);
      },
      beforeUnmount (el, binding) {
        // 解除事件监听
        document.removeEventListener("click", el.__vueClickOutside__);
        delete el.__vueClickOutside__;
      }
    };
    
    export default clickoutside;
    
    # 页面input自动聚焦
    const focus = {
      mounted (el) {
        el.querySelector("input").focus();
      }
    };
    
    export default focus;
    
    # 定义一个延迟执行的方法,如果在延迟时间内再调用该方法,则重新计算执行时间。  
    
    
    const debounce = {
      inserted: function (el, binding) {
        let timer
        el.addEventListener('keyup', () => {
          if (timer) {
            clearTimeout(timer)
          }
          timer = setTimeout(() => {
            binding.value()
          }, 1000)
        })
      },
    }
    
    export default debounce
    
    
    • 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
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    哈喽,喜欢这篇文章的话烦请点个赞哦!万分感谢(^▽^)PS:有问题可以联系我们哦v ceshiren001

    复制“下方链接”,提升测试核心竞争力!
    更多技术文章分享和免费资料领取

    总结

    自定义指令的第二用处是用于集成第三方插件。我们知道任何软件开发领域都可以分为四层:底层是原生的API,上层是通用框架,再上层是通用组件,最上层才是具体的业务代码。一个通用框架,必须搭配一套完整的通用组件,才能真正奠定其江湖地位。

    在前端开发领域,以前的通用框架是jQuery,jQuery以及基于jQuery构建的通用组件形成了一个庞大的生产系统。现在的通用框架是Angular、React和Vue,每个框架都需要基于自身构建新的组件库。自定义指令好就好在:原先的那些通用组件,无论是纯js的也好,基于jQuery的也好,都可以拿来主义直接吸收,而不需要改造或重构。

    比如写文档通常会用到focus.js,我们可以直接将其封装为一个自定义指令,这样focus.js就变成了Vue的一个新功能。

  • 相关阅读:
    【OBS】stream-labs-desktop 编译运行采坑全攻略
    gitlab 离线安装问题解决:NOKEY,signature check fail
    注册【小程序】和注册页面
    ChatGPT如何助力科研创新,提升研究效率?
    【算法题】小红书2023秋招提前批算法真题解析
    gRPC(八)生态 grpc-gateway 应用:同一个服务端支持Rpc和Restful Api
    启动 React APP 后经历了哪些过程
    Spring IoC
    UE4 C++设计模式:原型模式(Prototype Pattern)
    R语言绘图—“金字塔图”
  • 原文地址:https://blog.csdn.net/Tester_muller/article/details/126295546