前言
在 vue,除了核心功能默认内置的指令 ( v-model 和 v-show ),vue 也允许注册自定义指令。它的作用价值在于当开发人员在某些场景下需要对普通 DOM 元素进行操作。
Vue 自定义指令有全局注册和局部注册两种方式。先来看看注册全局指令的方式,通过 Vue.directive( id, [definition] ) 方式注册全局指令。然后在入口文件中进行 Vue.use() 调用。
提示:以下是本篇文章正文内容,下面案例可供参考
一、新建文件夹
在开始之前先把目录结构梳理一下,新建目录 directives 用于存放 自定义指令,其中
- index.js 为directives的主文件,全局注册的也是它
- copy.js 用于 实现 复制
- longpress.js 用于 实现 长按
- waterMarker.js 用于 实现 水印功能
目录结构截图
二、新建文件
在上述步骤新建完目录后,开始按照目录结构 新建 具体的文件,首先
directives -> index.js
import copy from "./copy"; import longpress from "./longpress"; import waterMarker from "./waterMarker"; // 自定义指令 const directives = { copy, longpress, waterMarker, }; export default { install(Vue) { Object.keys(directives).forEach((key) => { Vue.directive(key, directives[key]); }); }, };
1、v-copy
需求:
实现一键复制文本内容,用于鼠标右键粘贴。
思路:
- 动态创建 textarea 标签,并设置 readOnly 属性及移出可视区域
- 将要复制的值赋给 textarea 标签的 value 属性,并插入到 body
- 选中值 textarea 并复制
- 将 body 中插入的 textarea 移除
- 在第一次调用时绑定事件,在解绑时移除事件
copy.js
const copy = { bind(el, { value }) { el.$value = value; el.handler = () => { if (!el.$value) { // 值为空的时候,给出提示。可根据项目UI仔细设计 console.log("无复制内容"); 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) { console.log("复制成功"); // 可根据项目UI仔细设计 } document.body.removeChild(textarea); }; // 绑定点击事件,就是所谓的一键 copy 啦 el.addEventListener("click", el.handler); }, // 当传进来的值更新的时候触发 componentUpdated(el, { value }) { el.$value = value; }, // 指令与元素解绑的时候,移除事件绑定 unbind(el) { el.removeEventListener("click", el.handler); }, }; export default copy;
v-copy 复制 使用
vue单文件
<template> <button v-copy="copyText">复制</button> </template> <script> export default { data() { return { copyText: 'a copy directives', } }, } </script>
2、v-longpress
需求:
实现长按,用户需要按下并按住按钮几秒钟,触发相应的事件
思路:
- 创建一个计时器, 2 秒后执行函数
- 当用户按下按钮时触发 mousedown 事件,启动计时器;用户松开按钮时调用 mouseout 事件。
- 如果 mouseup 事件 2 秒内被触发,就清除计时器,当作一个普通的点击事件
- 如果计时器没有在 2 秒内清除,则判定为一次长按,可以执行关联的函数。
- 在移动端要考虑 touchstart,touchend 事件
longpress.js
const longpress = { bind: function (el, binding, vNode) { if (typeof binding.value !== "function") { throw "callback must be a function"; } // 定义变量 let pressTimer = null; // 创建计时器( 2秒后执行函数 ) let start = (e) => { if (e.type === "click" && e.button !== 0) { return; } if (pressTimer === null) { pressTimer = setTimeout(() => { handler(); }, 2000); } }; // 取消计时器 let cancel = (e) => { if (pressTimer !== null) { clearTimeout(pressTimer); pressTimer = null; } }; // 运行函数 const handler = (e) => { 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); }, // 当传进来的值更新的时候触发 componentUpdated(el, { value }) { el.$value = value; }, // 指令与元素解绑的时候,移除事件绑定 unbind(el) { el.removeEventListener("click", el.handler); }, }; export default longpress;
v-longpress 长按 使用
vue单文件
<template> <button v-longpress="longpress">长按</button> </template> <script> export default { methods: { longpress () { alert('长按指令生效') } } } </script>
3、vue-waterMarker
需求:给整个页面添加背景水印
思路:
- 使用 canvas 特性生成 base64 格式的图片文件,设置其字体大小,颜色等。
- 将其设置为背景图片,从而实现页面或组件水印效果
waterMarker.js
function addWaterMarker(str, parentNode, font, textColor) { // 水印文字,父元素,字体,文字颜色 var can = document.createElement("canvas"); parentNode.appendChild(can); can.width = 200; can.height = 150; can.style.display = "none"; var cans = can.getContext("2d"); 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"; cans.fillText(str, can.width / 10, can.height / 2); parentNode.style.backgroundImage = "url(" + can.toDataURL("image/png") + ")"; } const waterMarker = { bind: function (el, binding) { addWaterMarker( binding.value.text, el, binding.value.font, binding.value.textColor ); }, }; export default waterMarker;
v-waterMarker 水印 使用
vue单文件
<template> <div v-waterMarker="{text:'amoureux555版权所有',textColor:'rgba(180, 180, 180, 0.4)'}"></div> </template> <style scoped> div{ height: 800px; } </style>
水印效果图
总结
需用使用的指令按需引入,不需要的把index.js里引入的注释掉就好,注意
:要注释两个
地方!
下班~