每天一小步 <何为自定义指令>

118 阅读3分钟

前言

最近在准备面试,于是狂刷面试题,深感前端内卷之深以及个人知识之浅薄,于是想着开一个个人专题来加深一下面试题的记忆,防止猪脑过载给忘光了

Vue指令是什么?

使用过Vue的开发者对自定义指令这个词一定不会陌生,常用的v-bindv-show等都属于自定义指令,都是在Vue中默认注册的。

Vue的编译引擎在解析模板的时候,首先把DOM元素给解析成一个AST对象,里面包含了为该元素绑定的指令;然后将指令的钩子函数添加到vnode的回调函数中;最后在执行createElm函数生成真实DOM时根据vnode的回调队列执行指令的内容。(详情看Vue指令实现原理

自定义指令的钩子函数

胡乱分析一通,最后还是得靠手撕才能真的理解透彻。

想要创建一个自定义指令,首先需要了解以下两点(以下介绍为Vue3版本):

自定义指令的钩子函数

正如上面分析中提到,Vue指令其实是通过创建钩子函数来实现对DOM的操作的,指令的钩子函数有以下几个:

  • created绑定元素的 attributes 前,和事件监听器调用前被调用
  • beforeMount绑定元素被插入到 DOM 前被调用
  • mounted绑定元素的父元素 和 绑定元素中的所有子元素 都挂载完成后被调用
  • beforeUpdate绑定元素的 父元素 更新前被调用
  • updated绑定元素的父元素 和 绑定元素的所有子元素 都更新完成后被调用
  • beforeUnmount绑定元素的父元素 被卸载前被调用
  • unmounted绑定元素的父元素 被卸载后被调用

自定义指令钩子函数的参数

指令钩子函数的参数有以下几个:

  • el:指令绑定到的元素。这可以用于直接操作 DOM。
  • binding:一个对象,包括以下几个属性
    • value:传给指令的值,如v-if='true'中,value为true
    • oldValue:历史值,仅在beforeUpdateupdated中使用,无论值是否修改都可用
    • arg:传递给指令的参数,如在v-model:myValue中,参数是'myValue'
    • modifiers:一个包含修饰符的对象,如在v-my-directive.foo.bar中,修饰对象为`{ foo: true, bar: true }
    • instance:使用该指令的组件实例
    • dir:指令的定义对象
  • vnode:代表绑定元素的底层VNode
  • prevNode:之前的渲染中代表指令所绑定的元素的VNode,仅在beforeUpdateupdated中可用

如何创建自定义指令

我想要达到的效果是通过自定义指令,达到点击一个纯文本DOM就能复制内容的效果,要达到这个目的需要经过那些步骤呢?

1. 初始化自定义指令

想要开飞机,首先得有一辆飞机。那么下面我就在Vue3中初始化一个自定义指令

// myDirective.js
const copy = {
    mounted: el => console.log(el),
};

export default copy;
// main.js
import copy from "./assets/myDirective";

app.directive("copy", copy);

到这里,我们只需要在随意一个DOM元素上绑定v-copy然后刷新页面,就会在控制台中看到输出了这个DOM元素,说明自定义指令已经初始完成

完善指令

接下来的步骤就很简单了,只需要在mounted钩子函数中获取到DOM元素的文本内容,然后调用copy方法即可

// myDirective.js
const copy = {
    mounted: el => {
        const copy = () => {
            if (!el.innerHTML) throw "无复制内容";
            // 由于chrome默认设置的原因,可能会出现无法使用clipboard的情况
            if (navigator.clipboard && window.isSecureContext) {
                navigator.clipboard.writeText(el.innerHTML).then(() => {
                    console.log("复制成功");
                });
            } else {
                const textarea = document.createElement("textarea");
                textarea.readOnly = "readonly";
                textarea.style.position = "absolute";
                textarea.style.left = "-99999px";
                // 赋值
                textarea.value = el.innerHTML;
                document.body.appendChild(textarea);
                textarea.select();
                const result = document.execCommand("copy");
                if (result) console.log("复制成功");
                document.body.removeChild(textarea);
            }
        };
        el.addEventListener("click", copy);
    },
};

效果👇

copy指令.gif 大功告成~

结语

没啥结语~

Vue2自定义指令

Vue3自定义指令

要是文中有任何错误或者需要修改的内容,烦请指出,希望我这个小菜鸡的个人理解不会误人子弟~