vue自定义指令-2

90 阅读3分钟

在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>

image.png

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指令相关的就到此结束了,之后如果再有好的常用的指令可封装再更新了