initHeader
This commit is contained in:
28
frontend/src/directives/index.ts
Normal file
28
frontend/src/directives/index.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
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;
|
||||
22
frontend/src/directives/modules/auth.ts
Normal file
22
frontend/src/directives/modules/auth.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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;
|
||||
37
frontend/src/directives/modules/copy.ts
Normal file
37
frontend/src/directives/modules/copy.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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__);
|
||||
}
|
||||
};
|
||||
|
||||
async function handleClick(this: any) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(this.copyData);
|
||||
} catch (err) {
|
||||
console.error("复制操作不被支持或失败: ", err);
|
||||
}
|
||||
ElMessage({
|
||||
type: "success",
|
||||
message: "复制成功"
|
||||
});
|
||||
}
|
||||
|
||||
export default copy;
|
||||
31
frontend/src/directives/modules/debounce.ts
Normal file
31
frontend/src/directives/modules/debounce.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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;
|
||||
49
frontend/src/directives/modules/draggable.ts
Normal file
49
frontend/src/directives/modules/draggable.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
需求:实现一个拖拽指令,可在父元素区域任意拖拽元素。
|
||||
|
||||
思路:
|
||||
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;
|
||||
49
frontend/src/directives/modules/longpress.ts
Normal file
49
frontend/src/directives/modules/longpress.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 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;
|
||||
41
frontend/src/directives/modules/throttle.ts
Normal file
41
frontend/src/directives/modules/throttle.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
需求:防止按钮在短时间内被多次点击,使用节流函数限制规定时间内只能点击一次。
|
||||
|
||||
思路:
|
||||
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;
|
||||
36
frontend/src/directives/modules/waterMarker.ts
Normal file
36
frontend/src/directives/modules/waterMarker.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
需求:给整个页面添加背景水印。
|
||||
|
||||
思路:
|
||||
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;
|
||||
Reference in New Issue
Block a user