前言

vue默认内置了v-model、v-if、v-show、v-html、v-text等指令,但是这些往往不足以满足我们实际项目开发中的场景,比如权限控制按钮、路由菜单,复制文字等功能,就需要我们自己自定义一些满足我们项目需求的指令了,那怎么封装自定义指令,并使用呢?我们先从封装指令的基础说起。

封装指令基础

钩子函数

  • bind:只调用一次,指令第一次绑定到元素时调用。可以进行一次性初始化设置。
  • inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已经被插入文档中)。
  • update:所在组件的VNode更新时调用,也可能发生在其子VNode更新之前。
  • componentUpdated:指令所在组件的VNode及其子VNode全部更新后调用。
  • unbind:只调用一次,指令与元素解绑时调用。

钩子函数参数

钩子函数参数包含了el、binding、vnode、oldVnode。

  • el:指令所绑定的元素,可以用来直接操作DOM。
  • binding:一个对象,包含以下属性
    • name:指令名。不包括v-前缀(如:v-copy的name为copy)。
    • value:指令的绑定值(如:v-copy='1 + 1'中,value值为2)。
    • oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子函数中可用,无论值是否改变都可用。
    • expression:字符串形式的指令表达式(如:v-copy='1 + 1',表达式为"1 + 1")。
    • arg:传给指令的参数(如:v-copy:dblclick中,arg的值为dblclick)。
    • modifiers:一个包含修饰符的对象(如:v-copy.dblclick.icon中,修饰符对象为:{dblclick: true, icon: true})。
  • vnode:Vue编译生成的虚拟节点。
  • oldVnode:上一个虚拟节点。仅在update和componentUpdated钩子函数中可用。

实际使用

复制指令(v-copy)

我们先看如何使用:

单击复制

<div v-copy>单击复制</div> // 默认复制div的文案
<div v-copy="copyStr">单击复制</div> // 复制指令里的内容(copyStr)

给el添加点击事件,判断binding的value值是否为空,若为空,默认获取绑定元素的文本内容

el.addEventListener("click", () => {
    let str = binding.value ? binding.value : el.innerText;

    handleClick(str);
});
el.style.cursor = "copy";

双击复制

<div v-copy:dblclick>双击复制</div> // 默认复制div的文案
<div v-copy:dblclick="copyStr">双击复制</div> // 复制指令里的内容(copyStr)

给el添加双击事件,判断binding的value值是否为空,若为空,默认获取绑定元素的文本内容

el.addEventListener("dblclick", () => {
    let str = binding.value ? binding.value : el.innerText;

    handleClick(str);
});
el.style.cursor = "copy";

点击icon复制

<div v-copy:icon>单击icon复制</div> // 默认复制div的文案
<div v-copy:icon="copyStr">单击icon复制</div> // 复制指令里的内容(copyStr)

判断el是否已经增加了icon,没有则增加i标签,放置icon,给icon增加点击事件,进行复制

if (el.hasIcon) return;

const iconElement = document.createElement("i");

iconElement.setAttribute("class", "el-icon-document-copy");
iconElement.setAttribute("style", "margin-left:5px");
el.appendChild(iconElement);
el.hasIcon = true;
iconElement.addEventListener("click", () => {
    let str = binding.value ? binding.value : el.innerText;

    handleClick(str);
});
iconElement.style.cursor = "copy";

handleClick 逻辑

判断是否有id为copyTarget的输入框,没有则创造一个id为copyTarget的输入框,然后进行选中,调用execCommand('copy')进行选中文字的复制。

function handleClick (text) {
    if (!document.getElementById("copyTarget")) {
        const copyTarget = document.createElement("input");

        copyTarget.setAttribute("id", "copyTarget");
        copyTarget.setAttribute("style", "position:fixed;top:0;left:0;opacity:0;z-index:-1000;");
        document.body.appendChild(copyTarget);
    }

    // 复制内容
    const input = document.getElementById("copyTarget");

    input.value = text;
    input.select(); // 选取文本域中的内容。
    // 调用execCommand()可以实现浏览器菜单的很多功能. 如保存文件,打开新文件,撤消、重做操作…
    document.execCommand("copy"); // 复制选中的文字到剪贴板;
    // Message.success("复制成功");
    Notification({
        title: "成功",
        message: `${text}已复制到剪切板`,
        type: "success"
    });
}

完整代码

import { Message, Notification } from "element-ui";

function handleClick (text) {
    if (!document.getElementById("copyTarget")) {
        const copyTarget = document.createElement("input");

        copyTarget.setAttribute("id", "copyTarget");
        copyTarget.setAttribute("style", "position:fixed;top:0;left:0;opacity:0;z-index:-1000;");
        document.body.appendChild(copyTarget);
    }

    // 复制内容
    const input = document.getElementById("copyTarget");

    input.value = text;
    input.select(); // 选取文本域中的内容。
    // 调用execCommand()可以实现浏览器菜单的很多功能. 如保存文件,打开新文件,撤消、重做操作…
    document.execCommand("copy"); // 复制选中的文字到剪贴板;
    // Message.success("复制成功");
    Notification({
        title: "成功",
        message: `${text}已复制到剪切板`,
        type: "success"
    });
}

const install = function (Vue) {
    Vue.directive("copy", {
        bind (el, binding) {
            if (binding.arg === "dblclick") { // 双击触发
                el.addEventListener("dblclick", () => {
                    let str = binding.value ? binding.value : el.innerText;

                    handleClick(str);
                });
                el.style.cursor = "copy";
            } else if (binding.arg === "icon") { // 点击icon触发
                if (el.hasIcon) return;

                const iconElement = document.createElement("i");

                iconElement.setAttribute("class", "el-icon-document-copy");
                iconElement.setAttribute("style", "margin-left:5px");
                el.appendChild(iconElement);
                el.hasIcon = true;
                iconElement.addEventListener("click", () => {
                    let str = binding.value ? binding.value : el.innerText;

                    handleClick(str);
                });
                iconElement.style.cursor = "copy";
            } else { // 单击触发
                el.addEventListener("click", () => {
                    let str = binding.value ? binding.value : el.innerText;

                    handleClick(str);
                });
                el.style.cursor = "copy";
            }
        }
    });
};

export default install;

权限操作指令(v-hasPermi)

  • 使用:<el-button v-hasPermi="['activity:school:add']">新增活动</el-button>
  • 从store获取用户的权限数组,判断此时binding的value值是否存在权限数组中,没有则进行按钮的隐藏。
  • 完整代码
import store from "@/store";

const allPermission = "*:*:*";
export function hasPermi(value){
    // return true;
    const permissions = store.getters && store.getters.permissions;
    if (value && value instanceof Array && value.length > 0) {
        const permissionFlag = value;
        const hasPermissions = permissions.some(permission => allPermission === permission || permissionFlag.includes(permission));
        if (!hasPermissions) {
            return false;
        }
        return true;
    }
    throw new Error("请设置操作权限标签值");
}


export default {
    inserted(el, binding) {
        const { value } = binding;
        if (!hasPermi(value)){
            el.parentNode && el.parentNode.removeChild(el);

        }
    }
};

总结

到此这篇关于vue自定义封装指令以及实际使用的文章就介绍到这了,更多相关vue自定义封装指令内容请搜索阿兔在线工具以前的文章或继续浏览下面的相关文章希望大家以后多多支持阿兔在线工具!

点赞(0)

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部