commit
1ce3308740
|
@ -0,0 +1,19 @@
|
||||||
|
import { App, Directive } from 'vue';
|
||||||
|
import copy from './modules/copy';
|
||||||
|
import existShow from './modules/existShow';
|
||||||
|
import vPrint from './modules/print';
|
||||||
|
import waterMarker from './modules/waterMarker';
|
||||||
|
|
||||||
|
const directivesList: { [key: string]: Directive } = { copy, waterMarker, existShow, vPrint };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 挂载自定义事件
|
||||||
|
*/
|
||||||
|
const directives = {
|
||||||
|
install: function (app: App<Element>) {
|
||||||
|
Object.keys(directivesList).forEach(key => {
|
||||||
|
app.directive(key, directivesList[key]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export default directives;
|
|
@ -0,0 +1,51 @@
|
||||||
|
import type { DirectiveBinding } from 'vue';
|
||||||
|
import { Directive } from 'vue';
|
||||||
|
|
||||||
|
interface ElType extends HTMLElement {
|
||||||
|
copyData: string | number; // 定义一个属性,用于存储需要复制的数据
|
||||||
|
__handleClick__: any; // 定义一个属性,用于存储事件处理函数
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * v-copy
|
||||||
|
* 复制某个值至剪贴板
|
||||||
|
* 接收参数:string类型/Ref<string>类型/Reactive<string>类型
|
||||||
|
*/
|
||||||
|
const copy: Directive = {
|
||||||
|
mounted(el: ElType, binding: DirectiveBinding) {
|
||||||
|
el.copyData = binding.value;
|
||||||
|
el.addEventListener('click', handelClick);
|
||||||
|
},
|
||||||
|
// 指令所在组件VNode 更新时触发
|
||||||
|
updated(el: ElType, binding: DirectiveBinding) {
|
||||||
|
el.copyData = binding.value; // 更新需要复制的数据
|
||||||
|
},
|
||||||
|
// 指令与元素绑定时触发
|
||||||
|
beforeMount(el: ElType) {
|
||||||
|
// 移除点击事件
|
||||||
|
el.removeEventListener('click', el.__handleClick__);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 点击事件
|
||||||
|
* @param this 当前作用域
|
||||||
|
*/
|
||||||
|
function handelClick(this: any) {
|
||||||
|
// 创建一个 input 元素
|
||||||
|
const input = document.createElement('input');
|
||||||
|
// 将需要复制的数据赋值给 input 的 value 属性
|
||||||
|
input.value = this.copyData.toLocaleString();
|
||||||
|
// 将 input 元素添加到 body 中
|
||||||
|
document.body.appendChild(input);
|
||||||
|
// 选中 input 元素中的文本
|
||||||
|
input.select();
|
||||||
|
// 执行复制操作
|
||||||
|
document.execCommand('Copy');
|
||||||
|
// 将 input 元素从 body 中移除
|
||||||
|
document.body.removeChild(input);
|
||||||
|
|
||||||
|
// TODO: 如需自定义请修改提示方式
|
||||||
|
alert('复制成功');
|
||||||
|
}
|
||||||
|
export default copy;
|
|
@ -0,0 +1,66 @@
|
||||||
|
import type { Directive } from 'vue';
|
||||||
|
interface ELType extends HTMLElement {
|
||||||
|
parentNode: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
需求:实现一个拖拽指令,可在父元素区域任意拖拽元素。
|
||||||
|
|
||||||
|
思路:
|
||||||
|
1、设置需要拖拽的元素为absolute,其父元素为relative。
|
||||||
|
2、鼠标按下(onmousedown)时记录目标元素当前的 left 和 top 值。
|
||||||
|
3、鼠标移动(onmousemove)时计算每次移动的横向距离和纵向距离的变化值,并改变元素的 left 和 top 值
|
||||||
|
4、鼠标松开(onmouseup)时完成一次拖拽
|
||||||
|
|
||||||
|
使用:在 Dom 上加上 v-draggable 即可
|
||||||
|
<div class="dialog-model" v-draggable></div>
|
||||||
|
*/
|
||||||
|
const draggable: Directive = {
|
||||||
|
mounted(el: ELType) {
|
||||||
|
// 将光标设置为“move”,将位置设置为“absolute”
|
||||||
|
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;
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { Directive } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 当关闭这个页面时提示是否退出,不需要传递参数
|
||||||
|
*/
|
||||||
|
const existShow: Directive = {
|
||||||
|
// 指令与元素绑定时触发
|
||||||
|
beforeMount() {
|
||||||
|
window.onbeforeunload = function (event) {
|
||||||
|
(event || window.event).returnValue = '确定离开此页吗?';
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default existShow;
|
|
@ -0,0 +1,23 @@
|
||||||
|
import type { DirectiveBinding } from 'vue';
|
||||||
|
import { Directive } from 'vue';
|
||||||
|
|
||||||
|
interface ElType extends HTMLElement {
|
||||||
|
copyData: string | number; // 定义一个属性,用于存储需要复制的数据
|
||||||
|
__handleClick__: any; // 定义一个属性,用于存储事件处理函数
|
||||||
|
}
|
||||||
|
|
||||||
|
const vPrint: Directive = {
|
||||||
|
mounted(el: ElType, binding: DirectiveBinding) {
|
||||||
|
el.copyData = binding.value;
|
||||||
|
el.addEventListener('click', handelClick);
|
||||||
|
},
|
||||||
|
beforeMount(el: ElType) {
|
||||||
|
el.removeEventListener('click', el.__handleClick__);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function handelClick(this: any) {
|
||||||
|
print();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default vPrint;
|
|
@ -0,0 +1,46 @@
|
||||||
|
import type { Directive, DirectiveBinding } from 'vue';
|
||||||
|
|
||||||
|
/*
|
||||||
|
需求:给整个页面添加背景水印。
|
||||||
|
|
||||||
|
思路:
|
||||||
|
1、使用 canvas 特性生成 base64 格式的图片文件,设置其字体大小,颜色等。
|
||||||
|
2、将其设置为背景图片,从而实现页面或组件水印效果
|
||||||
|
|
||||||
|
使用:设置水印文案,颜色,字体大小即可
|
||||||
|
<div v-waterMarker="{text:'版权所有',textColor:'rgba(180, 180, 180, 0.4)'}"></div>
|
||||||
|
*/
|
||||||
|
const addWaterMarker: Directive = (str: string, parentNode: any, font: any, textColor: string) => {
|
||||||
|
// 创建一个canvas元素
|
||||||
|
let can: HTMLCanvasElement = document.createElement('canvas');
|
||||||
|
// 将canvas元素添加到父元素中
|
||||||
|
parentNode.appendChild(can);
|
||||||
|
// 设置canvas元素的宽高
|
||||||
|
can.width = 205;
|
||||||
|
can.height = 140;
|
||||||
|
// 隐藏canvas元素
|
||||||
|
can.style.display = 'none';
|
||||||
|
// 获取canvas元素的2d上下文
|
||||||
|
let cans = can.getContext('2d') as CanvasRenderingContext2D;
|
||||||
|
// 旋转canvas元素
|
||||||
|
cans.rotate((-20 * Math.PI) / 180);
|
||||||
|
// 设置canvas元素的字体和文字颜色
|
||||||
|
cans.font = font || '16px Microsoft JhengHei';
|
||||||
|
cans.fillStyle = textColor || 'rgba(180, 180, 180, 0.3)';
|
||||||
|
// 设置canvas元素的文本对齐方式和基线
|
||||||
|
cans.textAlign = 'left';
|
||||||
|
cans.textBaseline = 'Middle' as CanvasTextBaseline;
|
||||||
|
// 在canvas元素上绘制文本
|
||||||
|
cans.fillText(str, can.width / 10, can.height / 2);
|
||||||
|
// 将父元素的背景图片设置为canvas元素的dataURL
|
||||||
|
parentNode.style.backgroundImage = `url("${can.toDataURL('image/png')}")`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const waterMarker: Directive = {
|
||||||
|
mounted(el: DirectiveBinding, binding: DirectiveBinding) {
|
||||||
|
// 调用addWaterMarker函数,给元素添加水印
|
||||||
|
addWaterMarker(binding.value.text, el, binding.value.font, binding.value.textColor);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default waterMarker;
|
|
@ -1,3 +1,4 @@
|
||||||
|
import directives from '@/directives';
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
import { createApp } from 'vue';
|
import { createApp } from 'vue';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
|
@ -8,5 +9,5 @@ import router from './router';
|
||||||
const pinia = createPinia();
|
const pinia = createPinia();
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
app.use(router).use(pinia)
|
app.use(router).use(pinia).use(directives);
|
||||||
app.mount('#app');
|
app.mount('#app');
|
||||||
|
|
|
@ -1,4 +1,24 @@
|
||||||
<template>sdasd</template>
|
<template>
|
||||||
|
<textarea type="text" v-model="myData.inputValue" />
|
||||||
|
<button v-copy="myData.copyValue" @click="handelClik">点击复制</button>
|
||||||
|
<button v-vPrint>点击打印</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
<style scoped lang="scss"></style>
|
import { reactive } from 'vue';
|
||||||
|
const myData = reactive({
|
||||||
|
inputValue: '我是被复制的内容 🍒🍇🍊,2023-4-21 14:02:59',
|
||||||
|
copyValue: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const handelClik = () => {
|
||||||
|
myData.copyValue = myData.inputValue;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
textarea {
|
||||||
|
width: 500px;
|
||||||
|
height: 300px;
|
||||||
|
outline: 1px solid #f4dde5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<h1>bunny/default页面</h1>
|
<div v-waterMarker="{ text: 'Bunny Admin', textColor: 'rgba(180, 180, 180, 0.6)' }" v-existShow>
|
||||||
<RouterView />
|
<h1 @click="handelClik">bunny/default页面</h1>
|
||||||
|
<My />
|
||||||
|
<RouterView />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
import My from '@/views/bunny/default/My.vue';
|
||||||
|
|
||||||
|
const handelClik = () => {
|
||||||
|
print();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
Loading…
Reference in New Issue