当前位置:首页 > 科技  > 软件

Vue3问题:如何在页面上添加水印?

来源: 责编: 时间:2024-03-19 09:24:20 289观看
导读1. 需求分析为了防止网站信息被盗用,以及维护版权标识,常常需要在页面、图片或视频上添加独特水印,以作区分。同时,水印的添加不仅仅满足于添加,有时候还要能防止用户恶意篡改,时刻保证水印的功效。所以,这次问题我分为了两

kgy28资讯网——每日最新资讯28at.com

1. 需求分析

为了防止网站信息被盗用,以及维护版权标识,常常需要在页面、图片或视频上添加独特水印,以作区分。kgy28资讯网——每日最新资讯28at.com

同时,水印的添加不仅仅满足于添加,有时候还要能防止用户恶意篡改,时刻保证水印的功效。kgy28资讯网——每日最新资讯28at.com

所以,这次问题我分为了两种情况:一种是仅添加水印仅可,另一种是添加水印且要防篡改。kgy28资讯网——每日最新资讯28at.com

下面我将把实现一一列出。kgy28资讯网——每日最新资讯28at.com

kgy28资讯网——每日最新资讯28at.com

2. 实现步骤

(1)仅添加水印情况

对于仅需要添加水印的情况,直接使用第三方UI库中的水印组件即可,简单快速。kgy28资讯网——每日最新资讯28at.com

当然,我们也可以选择自己造轮子,用Canvas来画,但是对于工作而言,我觉得这样应该尽量避免。kgy28资讯网——每日最新资讯28at.com

这里我使用ElementPlus 2.4.0中,新出的Watermark水印组件作为例子。kgy28资讯网——每日最新资讯28at.com

实现代码:kgy28资讯网——每日最新资讯28at.com

<template><el-watermark:width="130":height="30"image="https://element-plus.org/images/element-plus-logo.svg"><div style="height: 500px" /></el-watermark></template>

效果如下:kgy28资讯网——每日最新资讯28at.com

kgy28资讯网——每日最新资讯28at.com

当然要注意的是,ElementPlus的依赖版本一定要是2.4.0之后的。kgy28资讯网——每日最新资讯28at.com

(2)添加水印且要防篡改情况

像ElementPlus提供的水印组件,是不支持防篡改功能的。kgy28资讯网——每日最新资讯28at.com

也就是说,如果有用户通过浏览器的控制台进行元素属性的修改,是可以把页面中的水印隐藏的。所以为了安全起见,是很需要做防篡改处理的。kgy28资讯网——每日最新资讯28at.com

为了保证自定义水印的灵活性,这里我使用了原生js的写法,并且代码参考了渡一官方大佬的文章。kgy28资讯网——每日最新资讯28at.com

简言之,就是利用Canvas绘制水印图像,以及利用MutationObserver对象来监听Dom节点或其子节点的变化以实现防篡改处理。kgy28资讯网——每日最新资讯28at.com

代码实现如下:kgy28资讯网——每日最新资讯28at.com

先写一个hook函数useWatermarkBg,在其中用Canvas绘制水印图像。kgy28资讯网——每日最新资讯28at.com

import { computed } from 'vue';export default function useWatermarkBg (props) {return computed(() => {// 创建一个 canvasconst canvas = document.createElement('canvas');const devicePixelRatio = window.devicePixelRatio || 1;// 设置字体大小const fontSize = props.fontSize * devicePixelRatio;const font = fontSize + 'px serif';const ctx = canvas.getContext('2d');// 获取文字宽度ctx.font = font;const { width } = ctx.measureText(props.text);const canvasSize = Math.max(100, width) + props.gap * devicePixelRatio;canvas.width = canvasSize;canvas.height = canvasSize;ctx.translate(canvas.width / 2, canvas.height / 2);// 旋转 45 度让文字变倾斜ctx.rotate((Math.PI / 180) * -45);ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';ctx.font = font;ctx.textAlign = 'center';ctx.textBaseline = 'middle';// 将文字画出来ctx.fillText(props.text, 0, 0);return {base64: canvas.toDataURL(),size: canvasSize,styleSize: canvasSize / devicePixelRatio,};});}

再封装一个水印公共组件WaterMark,在其中调用useWatermarkBg函数生成水印图像,以及添加水印、做防篡改处理。kgy28资讯网——每日最新资讯28at.com

在mounted中,创建MutationObserver实例,监听水印DOM节点的变化,在节点删除或属性修改时设置依赖,发出重新添加水印的通知。kgy28资讯网——每日最新资讯28at.com

在watchEffect中,进行收集依赖,只要依赖变化了,它就会重新添加水印图像,达到防篡改效果。kgy28资讯网——每日最新资讯28at.com

值得一提的是,因为添加水印的原理是给页面添加一个绝对定位的重复水印背景的div,但是,如果这样我们就不能点击div下层的元素了。kgy28资讯网——每日最新资讯28at.com

所以,这里还用了一个叫pointerEvents的css属性,设置值为none,从而使元素不会接收鼠标事件,鼠标事件会透过元素传递到下层的元素上。kgy28资讯网——每日最新资讯28at.com

<template><div class="watermark-container" ref="parentRef"><slot></slot></div></template><script setup>import { onMounted, onUnmounted, ref, watchEffect } from 'vue';import useWatermarkBg from '@/hooks/useWatermarkBg.js';const props = defineProps({text: {type: String,required: true,default: 'watermark',},fontSize: {type: Number,default: 40,},gap: {type: Number,default: 20,},});const bg = useWatermarkBg(props);const parentRef = ref(null);const flag = ref(0); // 声明一个依赖let div;watchEffect(() => {flag.value; // 将依赖放在 watchEffect 里if (!parentRef.value) {return;}if (div) {div.remove();}const { base64, styleSize } = bg.value;div = document.createElement('div');div.style.backgroundImage = `url(${base64})`;div.style.backgroundSize = `${styleSize}px ${styleSize}px`;div.style.backgroundRepeat = 'repeat';div.style.zIndex = 9999;div.style.position = 'absolute';div.style.inset = 0;// 元素不会接收鼠标事件,鼠标事件会透过元素传递到下层的元素上div.style.pointerEvents = 'none';parentRef.value.appendChild(div);});// 防篡改处理let ob;onMounted(() => {ob = new MutationObserver((records) => {for (const record of records) {for (const dom of record.removedNodes) {if (dom === div) {flag.value++; // 删除节点的时候更新依赖return;}}if (record.target === div) {flag.value++; // 修改属性的时候更新依赖return;}}});ob.observe(parentRef.value, {childList: true,attributes: true,subtree: true,});});onUnmounted(() => {ob && ob.disconnect();div = null;});</script>

最后,在需要添加水印的页面直接使用即可。kgy28资讯网——每日最新资讯28at.com

<template><water-mark><video src="@/assets/a.mp4" controls width="500" height="500"></video></water-mark></template><script setup>import WaterMark from "@/components/WaterMark.vue"</script>

3. 问题详解

(1)关于MutationObserver总结

MutationObserver 是 JavaScript 中的一个内置对象,它提供了一种监视 DOM(文档对象模型)树变化的能力。kgy28资讯网——每日最新资讯28at.com

MutationObserver 允许开发者注册一个回调函数,当观察的 DOM 节点或子节点发生变化时,会触发这个回调函数。这些变化可以包括节点的添加、移除、属性的变化、文本内容的改变等。kgy28资讯网——每日最新资讯28at.com

使用 MutationObserver 可以监视特定的 DOM 元素或整个文档,并在相关变化发生时执行相应的操作。这对于实时监测页面变化、自动化测试、实现响应式 UI 等场景非常有用。kgy28资讯网——每日最新资讯28at.com

下面是一个简单的示例,演示如何使用 MutationObserver 监测某个元素的子节点变化:kgy28资讯网——每日最新资讯28at.com

// 目标元素var targetElement = document.getElementById('target-element');// 创建一个 MutationObserver 实例var observer = new MutationObserver(function(mutationsList, observer) {// 当变化发生时执行的回调函数for (var mutation of mutationsList) {if (mutation.type === 'childList') {console.log('子节点发生变化');console.log(mutation.addedNodes); // 添加的节点列表console.log(mutation.removedNodes); // 移除的节点列表}}});// 配置观察选项var config = { childList: true };// 开始观察目标元素observer.observe(targetElement, config);

在上述示例中,我们首先通过 getElementById 获取目标元素,然后创建一个 MutationObserver 实例,传入一个回调函数作为参数。回调函数会在目标元素的子节点发生变化时被调用。我们可以在回调函数中根据 mutationsList 的内容进行相应的处理。在这个示例中,我们只关注子节点的变化,并打印相关信息到控制台。kgy28资讯网——每日最新资讯28at.com

最后,我们通过调用 observe 方法来开始观察目标元素的变化。在 config 对象中,我们将 childList 属性设置为 true,表示我们要监测子节点的变化。kgy28资讯网——每日最新资讯28at.com

需要注意的是,MutationObserver 是一个异步的机制,它会在变化发生后才触发回调函数。这意味着在开始观察之前的变化可能不会被捕获到。如果需要在开始观察之前立即获取当前状态的变化,可以在创建 MutationObserver 实例后,使用 observer.takeRecords() 方法来获取当前的变化记录。kgy28资讯网——每日最新资讯28at.com

(2)关于pointer-events的总结

pointer-events 是一种 CSS 属性,它控制元素对鼠标事件的响应方式。它可以设置在任何 HTML 元素上,并具有以下几个可能的取值:kgy28资讯网——每日最新资讯28at.com

  • auto:元素对鼠标事件作出默认的响应。即元素会根据自身的样式和内容对鼠标事件做出适当的响应。
  • none:元素对鼠标事件不做出响应。即元素不会接收鼠标事件,鼠标事件会透过元素传递到下层的元素上。这相当于将元素变为不可点击,即使它位于页面上方或遮挡其他元素。
  • visiblePainted:元素对鼠标事件做出响应,但鼠标事件不会穿透元素,而是传递到下层的元素上。这意味着元素会接收鼠标事件,但不会阻止下层元素对鼠标事件的响应。
  • visibleFill:元素对鼠标事件做出响应,并会阻止鼠标事件传递到下层的元素上。这意味着元素会完全接收鼠标事件,并阻止下层元素对鼠标事件的响应。

pointer-events 属性对于创建交互式的页面元素非常有用,可以控制元素是否能够接收和响应鼠标事件。通过将其设置为 none,可以使元素在外观上可见,但不会干扰下层元素的交互。kgy28资讯网——每日最新资讯28at.com

需要注意的是,pointer-events 属性的兼容性有限,可能不支持所有浏览器或旧版本的浏览器。在使用时,建议先检查兼容性并提供备用方案或降级策略。kgy28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-77681-0.htmlVue3问题:如何在页面上添加水印?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 详解基于SpringBoot的WebSocket应用开发

下一篇: C# WinForm程序中读写INI配置文件的技术详解

标签:
  • 热门焦点
  • 官方承诺:K60至尊版将会首批升级MIUI 15

    全新的MIUI 15今天也有了消息,在官宣了K60至尊版将会搭载天玑9200+处理器和独显芯片X7的同时,Redmi给出了官方承诺,K60至尊重大更新首批升级,会首批推送MIUI 15。也就是说虽然
  • 5月iOS设备好评榜:iPhone 14仅排第43?

    来到新的一月,安兔兔的各个榜单又重新汇总了数据,像安卓阵营的榜单都有着比较大的变动,不过iOS由于设备的更新换代并没有那么快,所以相对来说变化并不大,特别是iOS好评榜,老款设
  • 让我们一起聊聊文件的操作

    文件【1】文件是什么?文件是保存数据的地方,是数据源的一种,比如大家经常使用的word文档、txt文件、excel文件、jpg文件...都是文件。文件最主要的作用就是保存数据,它既可以保
  • 微信语音大揭秘:为什么禁止转发?

    大家好,我是你们的小米。今天,我要和大家聊一个有趣的话题:为什么微信语音不可以转发?这是一个我们经常在日常使用中遇到的问题,也是一个让很多人好奇的问题。让我们一起来揭开这
  • 使用Webdriver-manager解决浏览器与驱动不匹配所带来自动化无法执行的问题

    1、前言在我们使用 Selenium 进行 UI 自动化测试时,常常会因为浏览器驱动与浏览器版本不匹配,而导致自动化测试无法执行,需要手动去下载对应的驱动版本,并替换原有的驱动,可能还
  • 零售大模型“干中学”,攀爬数字化珠峰

    文/侯煜编辑/cc来源/华尔街科技眼对于绝大多数登山爱好者而言,攀爬珠穆朗玛峰可谓终极目标。攀登珠峰的商业路线有两条,一是尼泊尔境内的南坡路线,一是中国境内的北坡路线。相
  • 重估百度丨“晚熟”的百度云,能等到春天吗?

    &copy;自象限原创作者|程心排版|王喻可2016年7月13日,百度云计算战略发布会在北京举行,宣告着百度智能云的正式启程。彼时的会场座无虚席,甚至排队排到了门外,在场的所有人几乎都
  • 最薄的14英寸游戏笔记本电脑 Alienware X14已可以购买

    2022年1月份在国际消费电子展(CES2022)上首次亮相的Alienware新品——Alienware X14现在已经可以购买了,这款笔记本电脑被誉为世界上最薄的 14 英寸游戏笔
  • 利用职权私自解除被封帐号 Meta开除20多名员工

    11月18日消息,据外媒援引知情人士表示,过去一年时间内,Facebook母公司Meta解雇或处罚了20多名员工以及合同工,指控这些人通过内部系统以不当方式重置用户帐号,其
Top