在vue自定义指令中对指令做了一些基本的铺垫,所以在本文就直接写其它自定义指令的实现了,篇1快速入口==> vue自定义指令-1 - 掘金 (juejin.cn)
其实这些指令都挺简单的,如果你用原生JS写过这些东西的话,那我可以很明确的告诉你,除了要封装成任意元素绑定指令之后都能触发该指令之外,其它的和你正常写JS实现没啥区别...
v-clickcopy 点击复制
/**
* v-clickcopy
* 点击复制某个值至剪贴板
*/
import type { Directive, DirectiveBinding } from "vue";
import { ElMessage } from "element-plus";
// TS类型限制
interface ElType extends HTMLElement {
copyData: string | number;
__handleClick__: any;
}
const clickcopy: 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 clickcopy;
使用
v-clickcopy 接收一个参数,该参数是要复制的内容
<template>
<h1>复制指令</h1>
<hr>
<br>
<!-- 用法1: -->
<input placeholder="请输入内容" v-model="data" type="text" name="" id="">
<button v-clickcopy="data">复制</button>
<!-- 用法2: -->
<h2 v-clickcopy=" '复制指令用法2' ">请输入内容</h2>
</template>
<script setup lang="ts">
import { ref } from "vue";
const data = ref<string>("神也慕我小七");
</script>
<style scoped lang="scss">
</style>
v-selectcopy 鼠标滑动选中复制
/**
* v-selectcopy
* 鼠标选中文字即可复制
* 使用:
* <h2 v-selectcopy>神也慕我小七</h2>
*/
import type { Directive, DirectiveBinding } from "vue";
import { ElMessage } from "element-plus";
const selectcopy: Directive = {
mounted(el: HTMLElement, binding: DirectiveBinding) {
el.addEventListener("mouseup", handleMouseSelect);
},
beforeUnmount(el: HTMLElement) {
el.removeEventListener("mouseup", handleMouseSelect);
},
};
function handleMouseSelect(this: any) {
// 获取用户选中的文字
let text = window.getSelection()!.toString();
// 创建一个 input 标签
const input = document.createElement("input");
// 将选中的文字放到 input 中
input.value = text;
// 在页面中插入 input 标签
document.body.appendChild(input);
// 选中 input 中的内容
input.select();
// 复制到剪切板中
document.execCommand("copy");
// 删除前面创造的 input 标签
document.body.removeChild(input);
// 提示用户
ElMessage({
type: "success",
message: "复制成功",
});
}
export default selectcopy;
使用
<h2 v-selectcopy>神也慕我小七</h2>
v-throttle 节流指令
/*
使用:给 Dom 加上 v-throttle 及回调函数即可
<button v-throttle="cb">节流提交</button>
*/
import type { Directive, DirectiveBinding } from "vue";
// ts 类型限制
interface ElType extends HTMLElement {
__cb__: () => any;
disabled: boolean;
}
const throttle: Directive = {
mounted(el: ElType, binding: DirectiveBinding) {
if (typeof binding.value !== "function") {
throw "回调应该是一个函数!";
}
let timer: any = null;
el.__cb__ = function () {
if (timer) {
clearTimeout(timer);
}
if (!el.disabled) {
el.disabled = true;
binding.value();
timer = setTimeout(() => {
el.disabled = false;
}, 1000);
}
};
el.addEventListener("click", el.__cb__);
},
beforeUnmount(el: ElType) {
el.removeEventListener("click", el.__cb__);
},
};
export default throttle;
v-debounce 防抖指令
/**
* v-debounce
* 按钮防抖指令,可自行扩展至input
* 接收参数:function类型
*/
import type { Directive, DirectiveBinding } from "vue";
interface ElType extends HTMLElement {
__cb__: () => any;
}
const debounce: Directive = {
mounted(el: ElType, binding: DirectiveBinding) {
if (typeof binding.value !== "function") {
throw "callback must be a function";
}
let timer: any = null;
el.__cb__ = function () {
if (timer) {
clearInterval(timer);
}
timer = setTimeout(() => {
binding.value();
}, 500);
};
el.addEventListener("click", el.__cb__);
},
beforeUnmount(el: ElType) {
el.removeEventListener("click", el.__cb__);
}
};
export default debounce;
v-draggable 拖拽指令
/*
*使用:在 Dom 上加上 v-draggable 即可
*<div 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;
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 timer: any = null;
// 创建计时器( 2秒后执行函数 )
const start = (e: any) => {
if (e.button) {
if (e.type === "click" && e.button !== 0) {
return;
}
}
if (timer === null) {
timer = setTimeout(() => {
handler(e);
}, 2000);
}
};
// 取消计时器
const cancel = () => {
if (timer !== null) {
clearTimeout(timer);
timer = 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;
入口文件中注册指令
import clickcopy from "./modules/clickcopy";
import selectcopy from "./modules/selectcopy";
import draggable from "./modules/draggable";
import debounce from "./modules/debounce";
import throttle from "./modules/throttle";
import longpress from "./modules/longpress";
import imglazy from "./modules/imglazy";
import permission from "./modules/permission";
const directivesList: any = {
clickcopy,
draggable,
debounce,
throttle,
longpress,
imglazy,
permission,
selectcopy
};
const directives = {
install: function (app: any) {
Object.keys(directivesList).forEach(key => {
// 注册所有自定义指令
app.directive(key, directivesList[key]);
});
}
};
export default directives;
main.ts 中挂载指令
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import './assets/main.css'
// 1. 引入
import directives from "@/directives/index";
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(ElementPlus)
// 2. use
app.use(directives)
app.mount('#app')
因为我觉得不难,所以就懒得写思路了。有需要的话可以私聊我。vue指令相关的就到此结束了,之后如果再有好的常用的指令可封装再更新了