vue超好用的自定义指令封装

一、指令封装

目录结构:

index.ts 统一注册

import { App, Directive } from "vue";
import auth from "./modules/auth";
import copy from "./modules/copy";
import waterMarker from "./modules/waterMarker";
import draggable from "./modules/draggable";
import debounce from "./modules/debounce";
import throttle from "./modules/throttle";
import longpress from "./modules/longpress";const directivesList: { [key: string]: Directive } = {auth,copy,waterMarker,draggable,debounce,throttle,longpress
};const directives = {install: function (app: App<Element>) {Object.keys(directivesList).forEach(key => {app.directive(key, directivesList[key]);});}
};export default directives;

记得use

二、自定义指令

1.防抖 v-debounce

/*** v-debounce* 按钮防抖指令,可自行扩展至input* 接收参数:function类型*/
import type { Directive, DirectiveBinding } from "vue";
interface ElType extends HTMLElement {__handleClick__: () => any;
}
const debounce: Directive = {mounted(el: ElType, binding: DirectiveBinding) {if (typeof binding.value !== "function") {throw "callback must be a function";}let timer: NodeJS.Timeout | null = null;el.__handleClick__ = function () {if (timer) {clearInterval(timer);}timer = setTimeout(() => {binding.value();}, 500);};el.addEventListener("click", el.__handleClick__);},beforeUnmount(el: ElType) {el.removeEventListener("click", el.__handleClick__);}
};export default debounce;

2.节流 v-throttle

/*需求:防止按钮在短时间内被多次点击,使用节流函数限制规定时间内只能点击一次。思路:1、第一次点击,立即调用方法并禁用按钮,等延迟结束再次激活按钮2、将需要触发的方法绑定在指令上使用:给 Dom 加上 v-throttle 及回调函数即可<button v-throttle="debounceClick">节流提交</button>
*/
import type { Directive, DirectiveBinding } from "vue";
interface ElType extends HTMLElement {__handleClick__: () => any;disabled: boolean;
}
const throttle: Directive = {mounted(el: ElType, binding: DirectiveBinding) {if (typeof binding.value !== "function") {throw "callback must be a function";}let timer: NodeJS.Timeout | null = null;el.__handleClick__ = function () {if (timer) {clearTimeout(timer);}if (!el.disabled) {el.disabled = true;binding.value();timer = setTimeout(() => {el.disabled = false;}, 1000);}};el.addEventListener("click", el.__handleClick__);},beforeUnmount(el: ElType) {el.removeEventListener("click", el.__handleClick__);}
};export default throttle;

3.复制 v-copy

/*** v-copy* 复制某个值至剪贴板* 接收参数:string类型/Ref<string>类型/Reactive<string>类型*/
import type { Directive, DirectiveBinding } from "vue";
import { ElMessage } from "element-plus";
interface ElType extends HTMLElement {copyData: string | number;__handleClick__: any;
}
const copy: Directive = {mounted(el: ElType, binding: DirectiveBinding) {el.copyData = binding.value;el.addEventListener("click", handleClick);},updated(el: ElType, binding: DirectiveBinding) {el.copyData = binding.value;},beforeUnmount(el: ElType) {el.removeEventListener("click", el.__handleClick__);}
};function handleClick(this: any) {const input = document.createElement("input");input.value = this.copyData.toLocaleString();document.body.appendChild(input);input.select();document.execCommand("Copy");document.body.removeChild(input);ElMessage({type: "success",message: "复制成功"});
}export default copy;

4.长按 v-longpress

/*** v-longpress* 长按指令,长按时触发事件*/
import type { Directive, DirectiveBinding } from "vue";const directive: Directive = {mounted(el: HTMLElement, binding: DirectiveBinding) {if (typeof binding.value !== "function") {throw "callback must be a function";}// 定义变量let pressTimer: any = null;// 创建计时器( 2秒后执行函数 )const start = (e: any) => {if (e.button) {if (e.type === "click" && e.button !== 0) {return;}}if (pressTimer === null) {pressTimer = setTimeout(() => {handler(e);}, 1000);}};// 取消计时器const cancel = () => {if (pressTimer !== null) {clearTimeout(pressTimer);pressTimer = null;}};// 运行函数const handler = (e: MouseEvent | TouchEvent) => {binding.value(e);};// 添加事件监听器el.addEventListener("mousedown", start);el.addEventListener("touchstart", start);// 取消计时器el.addEventListener("click", cancel);el.addEventListener("mouseout", cancel);el.addEventListener("touchend", cancel);el.addEventListener("touchcancel", cancel);}
};export default directive;

5.拖拽 v-draggable

/*需求:实现一个拖拽指令,可在父元素区域任意拖拽元素。思路:1、设置需要拖拽的元素为absolute,其父元素为relative。2、鼠标按下(onmousedown)时记录目标元素当前的 left 和 top 值。3、鼠标移动(onmousemove)时计算每次移动的横向距离和纵向距离的变化值,并改变元素的 left 和 top 值4、鼠标松开(onmouseup)时完成一次拖拽使用:在 Dom 上加上 v-draggable 即可<div class="dialog-model" v-draggable></div>
*/
import type { Directive } from "vue";
interface ElType extends HTMLElement {parentNode: any;
}
const draggable: Directive = {mounted: function (el: ElType) {el.style.cursor = "move";el.style.position = "absolute";el.onmousedown = function (e) {let disX = e.pageX - el.offsetLeft;let disY = e.pageY - el.offsetTop;document.onmousemove = function (e) {let x = e.pageX - disX;let y = e.pageY - disY;let maxX = el.parentNode.offsetWidth - el.offsetWidth;let maxY = el.parentNode.offsetHeight - el.offsetHeight;if (x < 0) {x = 0;} else if (x > maxX) {x = maxX;}if (y < 0) {y = 0;} else if (y > maxY) {y = maxY;}el.style.left = x + "px";el.style.top = y + "px";};document.onmouseup = function () {document.onmousemove = document.onmouseup = null;};};}
};
export default draggable;

6.水印 v-waterMarker

/*需求:给整个页面添加背景水印。思路:1、使用 canvas 特性生成 base64 格式的图片文件,设置其字体大小,颜色等。2、将其设置为背景图片,从而实现页面或组件水印效果使用:设置水印文案,颜色,字体大小即可<div v-waterMarker="{text:'版权所有',textColor:'rgba(180, 180, 180, 0.4)'}"></div>
*/import type { Directive, DirectiveBinding } from "vue";
const addWaterMarker: Directive = (str: string, parentNode: any, font: any, textColor: string) => {// 水印文字,父元素,字体,文字颜色let can: HTMLCanvasElement = document.createElement("canvas");parentNode.appendChild(can);can.width = 205;can.height = 140;can.style.display = "none";let cans = can.getContext("2d") as CanvasRenderingContext2D;cans.rotate((-20 * Math.PI) / 180);cans.font = font || "16px Microsoft JhengHei";cans.fillStyle = textColor || "rgba(180, 180, 180, 0.3)";cans.textAlign = "left";cans.textBaseline = "Middle" as CanvasTextBaseline;cans.fillText(str, can.width / 10, can.height / 2);parentNode.style.backgroundImage = "url(" + can.toDataURL("image/png") + ")";
};const waterMarker = {mounted(el: DirectiveBinding, binding: DirectiveBinding) {addWaterMarker(binding.value.text, el, binding.value.font, binding.value.textColor);}
};export default waterMarker;

7.按钮权限 v-auth

/*** v-auth* 按钮权限指令 (根据需求而定)*/
import { useAuthStore } from "@/stores/modules/auth";
import type { Directive, DirectiveBinding } from "vue";const auth: Directive = {mounted(el: HTMLElement, binding: DirectiveBinding) {const { value } = binding;const authStore = useAuthStore();const currentPageRoles = authStore.authButtonListGet[authStore.routeName] ?? [];if (value instanceof Array && value.length) {const hasPermission = value.every(item => currentPageRoles.includes(item));if (!hasPermission) el.remove();} else {if (!currentPageRoles.includes(value)) el.remove();}}
};export default auth;

8.旋转 v-rotate

// 自定义指令,点击旋转 v-rotate
const rotate = {beforeMount(el: any) {el.addEventListener("click", function () {console.log(el.style.transform);el.style.transition = "all 0.3s";if (el.style.transform) {let str = el.style.transform;let deg = str.substring(str.indexOf("(") + 1, str.indexOf("d"));el.style.transform = `rotate(${Number(deg) + 180}deg)`;} else {el.style.transform = "rotate(180deg)";}});}
};export default rotate;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/158383.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenStack-train版安装之基础组件安装

基础组件安装 安装MariaDB&#xff08;数据库&#xff09;安装RabbitMQ&#xff08;消息队列&#xff09;安装Memcached&#xff08;缓存&#xff09; 安装MariaDB&#xff08;数据库&#xff09; 安装 # yum install mariadb mariadb-server python2-PyMySQL -y数据库配置 …

2023年中国感应电炉产业链、产量、销量及市场规模分析[图]

感应电炉行业定义是指使用电磁感应原理&#xff0c;通过感应电流使金属工件在短时间内达到预定温度的工业设备。广泛应用于冶金、机械、汽车、航空、航天、船舶、电子、医疗器械等领域。 感应电炉行业产业链 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; …

CSS实现空心的“尖角”

大家好&#xff0c;我是南宫&#xff0c;来分享一个昨天解决的问题。 我记得之前刷面试题的时候&#xff0c;CSS面试题里面赫然有一题是“如何用CSS实现三角形”&#xff0c;我觉得这个问题确实很经典&#xff0c;我上的前端培训班当初就讲过。 大概思路如下&#xff1a; 先…

【每周一测】Java阶段三阶段考试

目录 1、SpringBoot在整合RabbitMQ时需要导入的包是 2、下列关于RabbitMQ的confirm消息确认机制解释说明正确的是 3、关于SpringBoot的配置文件&#xff0c;以下说法正确的是&#xff08;&#xff09; 4、变量命名规范说法正确的是? 5、哪个关键字可以对对象加互斥锁&…

优思学院|质量管理怎样才能做好?

质量管理怎样才能做好&#xff1f;这是一个好问题&#xff0c;很多人第一时间会想到建立一个稳定的质量管理体系&#xff0c;例如ISO9001&#xff0c;又或者善用QC七大手法等等&#xff0c;虽然以上这些方法都是实用和正确的&#xff0c;绝大多数企业通常最忽略的&#xff0c;其…

备案信息一键查询:网站备案信息查询API的操作与优势

前言 在当今数字化的时代&#xff0c;企业的在线存在至关重要。而为了确保在网络空间的法规合规性&#xff0c;了解和管理网站备案信息变得尤为重要。为了使这一过程更为高效、便捷&#xff0c;网站备案信息查询API应运而生&#xff0c;为企业提供了一种简便的方式来获取和管理…

如何打造适用的MES管理系统解决方案

在当前的制造业领域&#xff0c;项目型生产企业面临着独特的挑战。尽管国外的大型软件公司提供了某些解决方案&#xff0c;但由于地域、文化和制度的差异&#xff0c;这些方案并不完全满足企业的实际需求。为了解决这一难题&#xff0c;我们必须以客户为中心&#xff0c;围绕他…

数字逻辑电路基础-时序逻辑电路之锁存器

文章目录 一、锁存器简介二、verilog源码三、综合及仿真结果一、锁存器简介 本文介绍数字逻辑电路中一种常用的基础时序逻辑电路-锁存,顾名思义,它的功能就是将输入在控制信号有效时透明传输到输出端,当控制信号无效时,输出值保持不变。它具有记忆和存储功能。这是它区别组…

处理无线debug问题

无限debug的产生 条件说明 开发者工具是打开状态 js代码中有debugger js有定时处理 setInterval(() > {(function (a) {return (function (a) {return (Function(Function(arguments[0]" a ")()))})(a)})(bugger)(de, 0, 0, (0, 0)); }, 1000); ​ #这里就…

供应链和物流的自动化新时代

今天&#xff0c;当大多数人想到物流自动化时&#xff0c;他们会想到设备。机器人、无人机和自主卡车运输在大家的谈话中占主导地位。全自动化仓库的视频在网上流传&#xff0c;新闻主播们为就业问题绞尽脑汁。这种炒作是不完整的&#xff0c;它错过了供应链和物流公司的机会。…

Talk | PSU助理教授吴清云:AutoGen-用多智能体对话开启下一代大型语言模型应用

本期为TechBeat人工智能社区第548期线上Talk&#xff01; 北京时间11月21日(周二)20:00&#xff0c;宾夕法尼亚州立大学助理教授—吴清云的Talk已准时在TechBeat人工智能社区开播&#xff01; 她与大家分享的主题是: “ AutoGen&#xff1a;用多智能体对话开启下一代大型语言模…

4.2V升多串LED驱动升压6V9V12V恒流点灯

4.2V升多串LED驱动升压6V9V12V恒流点灯 探索WT7012&#xff0c;这款引领潮流的升压转换器&#xff0c;其强大功能将彻底改变您的LED驱动格局。可以轻松驾驭多达7串白光LED&#xff0c;展现出无与伦比的驱动能力。 无论是单节锂电池还是多节锂电池供电产品&#xff0c;宽电压3…

单链表相关面试题--5.合并有序链表

5.合并有序链表 21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09; /* 解题思路&#xff1a; 此题可以先创建一个空链表&#xff0c;然后依次从两个有序链表中选取最小的进行尾插操作进行合并。 */ typedef struct ListNode Node; struct ListNode* mergeTwoList…

使用 API 管理平台的 5 大理由

组织需要治理和控制API生态系统&#xff0c;这种治理就是API管理的作用。 Uber 使用 API​​&#xff08;应用程序编程接口&#xff09;与 Google Maps 和 Twilio 等第三方服务连接&#xff0c;这有助于改善用户体验&#xff1b; Salesforce 提供 API&#xff0c;允许开发人员…

虚函数可不可以重载为内联 —— 在开启最大优化时gcc、clang和msvc的表现

下面是对该问题的一种常见回答&#xff1a; 首先&#xff0c;内联是程序员对编译器的一种建议&#xff0c;因此可以在在重载虚函数时在声明处加上inline关键字来修饰&#xff0c; 但是因为虚函数在运行时通过虚函数表&#xff0c;而内联函数在编译时进行代码嵌入&#xff0c;因…

Linux wait函数用法

wait 函数是用于等待子进程结束并获取子进程的终止状态的系统调用。它在父进程中使用&#xff0c;用于等待其子进程终止并获得子进程的退出状态。 函数原型&#xff1a; pid_t wait(int *status);status 是一个指向整型的指针&#xff0c;用于存储子进程终止时的退出状态&…

redis的集群

高可用方案 1、持久化 2、高可用 主从复制 哨兵模式 集群 主从复制: 主从复制是redis实现高可用的基础&#xff0c;哨兵模式和集群都是在主从复制的基础之上实现高可用 主从复制实现数据的多机备份&#xff0c;以及读写分离&#xff08;主服务器负责写&#xff0c;从服务器…

RFID读写器在物联网中的应用与优势

随着物联网技术的不断发展&#xff0c;RFID读写器作为物联网感知层的重要组成部分&#xff0c;在各个领域得到了广泛应用。本文将介绍RFID读写器在物联网中的应用及优势。 一、RFID读写器概述 RFID&#xff08;Radio Frequency Identification&#xff09;技术是一种利用无线…

机器学习中的特征选择:方法和 Python 示例

布拉加德什桑达拉拉詹 一、说明 特征选择是机器学习流程中至关重要且经常被低估的步骤。它涉及从数据集中的原始特征集中选择最相关的特征&#xff08;输入变量或属性&#xff09;的子集。特征选择的重要性怎么强调都不为过&#xff0c;因为它直接影响机器学习模型的质量、效率…

leetcode 240. 搜索二维矩阵 II

2023.11.22 本题最先想到的是暴力法和二分法&#xff0c;暴力法就不写了&#xff0c;写一下二分法的解法&#xff0c;java代码如下&#xff1a; class Solution {public boolean searchMatrix(int[][] matrix, int target) {for(int[] row : matrix){int left 0;int right r…