diff --git a/src/directives/index.ts b/src/directives/index.ts new file mode 100644 index 0000000..634d804 --- /dev/null +++ b/src/directives/index.ts @@ -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) { + Object.keys(directivesList).forEach(key => { + app.directive(key, directivesList[key]); + }); + }, +}; +export default directives; diff --git a/src/directives/modules/copy.ts b/src/directives/modules/copy.ts new file mode 100644 index 0000000..347e134 --- /dev/null +++ b/src/directives/modules/copy.ts @@ -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类型/Reactive类型 + */ +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; diff --git a/src/directives/modules/draggable.ts b/src/directives/modules/draggable.ts new file mode 100644 index 0000000..e600b52 --- /dev/null +++ b/src/directives/modules/draggable.ts @@ -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 即可 +
+*/ +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; diff --git a/src/directives/modules/existShow.ts b/src/directives/modules/existShow.ts new file mode 100644 index 0000000..d7f9171 --- /dev/null +++ b/src/directives/modules/existShow.ts @@ -0,0 +1,15 @@ +import { Directive } from 'vue'; + +/** + * * 当关闭这个页面时提示是否退出,不需要传递参数 + */ +const existShow: Directive = { + // 指令与元素绑定时触发 + beforeMount() { + window.onbeforeunload = function (event) { + (event || window.event).returnValue = '确定离开此页吗?'; + }; + }, +}; + +export default existShow; diff --git a/src/directives/modules/print.ts b/src/directives/modules/print.ts new file mode 100644 index 0000000..177b4cf --- /dev/null +++ b/src/directives/modules/print.ts @@ -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; diff --git a/src/directives/modules/waterMarker.ts b/src/directives/modules/waterMarker.ts new file mode 100644 index 0000000..5d3951a --- /dev/null +++ b/src/directives/modules/waterMarker.ts @@ -0,0 +1,46 @@ +import type { Directive, DirectiveBinding } from 'vue'; + +/* + 需求:给整个页面添加背景水印。 + + 思路: + 1、使用 canvas 特性生成 base64 格式的图片文件,设置其字体大小,颜色等。 + 2、将其设置为背景图片,从而实现页面或组件水印效果 + + 使用:设置水印文案,颜色,字体大小即可 +
+*/ +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; diff --git a/src/main.ts b/src/main.ts index 27bd4af..20b727e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,3 +1,4 @@ +import directives from '@/directives'; import { createPinia } from 'pinia'; import { createApp } from 'vue'; import App from './App.vue'; @@ -8,5 +9,5 @@ import router from './router'; const pinia = createPinia(); const app = createApp(App); -app.use(router).use(pinia) +app.use(router).use(pinia).use(directives); app.mount('#app'); diff --git a/src/views/bunny/default/My.vue b/src/views/bunny/default/My.vue index 03f149c..9426076 100644 --- a/src/views/bunny/default/My.vue +++ b/src/views/bunny/default/My.vue @@ -1,4 +1,24 @@ - +