vue实现水印功能

目录

一、应用场景

二、实现原理

三、详细开发

1.水印的实现方式

2.防止用户通过控制台修改样式去除水印效果(可跳过,有弊端)

3.水印的使用

(1)单页面/全局使用

(2)全局使用+个别页面去掉

四、总结


一、应用场景

在网页中添加水印的作用可以有多个方面,一个重要的作用就是版权保护,防止未经授权就复制截图或使用,在文档中可以帮助标识文档的来源,审查追踪等,也可以展示企业信息,或者作为提示信息告诉用户当前页面谨慎处理,也能在敏感信息的页面提示用户保护信息安全等。注意:制作页面中的水印要平衡用户体验和需求,确保水印不要太大,太密,太突兀,干扰页面浏览和操作


二、实现原理

在页面里添加水印,一种是特定页面加水印,那么本页面加水印功能即可,用CSS/JavaScript都可以实现,另一种是全局都加水印,这种可以考虑某些页面不需要加水印,在路由守卫或者其他地方去掉即可。

写在前面,水印的实现原理创建一个canvas,画一个客户端高x客户端宽的画布,里面画满水印,并将其的层级z-index设置最高,使其一直显示在界面的最上方。

水印的内容,可以根据应用的场景而变换,比如版权保护,这些最好显示版权的归属方之类的,有些出于标识来源加的水印,则需要考虑当前用户的信息,比如用户名等等。

实现效果如下:


三、详细开发

首先谈一下水印的实现方式,再说怎么加水印。

1.水印的实现方式

我们可以在utils下新建一个文件:watermark.js,代码如下:

let watermark = {}
let idd = "1.23452384164.123412416"
let setWatermark = (str, srt1, srt2, srt3) => {let id = iddif (document.getElementById(id) !== null) {document.body.removeChild(document.getElementById(id))}//创建一个画布let can = document.createElement("canvas")//设置画布的长宽can.width = 600can.height = 450                                                                                   let cans = can.getContext("2d")//旋转角度cans.rotate((-15 * Math.PI) / 180)cans.font = "18px Vedana"//设置填充绘画的颜色、渐变或者模式cans.fillStyle = "rgba(200, 200, 200, 0.40)"//设置文本内容的当前对齐方式cans.textAlign = "left"//设置在绘制文本时使用的当前文本基线cans.textBaseline = "Middle"//在画布上绘制填色的文本(输出的文本,开始绘制文本的X坐标位置,开始绘制文本的Y坐标位置)cans.fillText(str + srt1, can.width / 8, can.height / 2)cans.fillText(srt2, can.width / 8, can.height / 2.3)cans.fillText(srt3, can.width / 8, can.height / 2.7)let div = document.createElement("div")div.id = idconst styleStr = `position:fixed;visibility:visible !important;top:30px;width:${document.documentElement.clientWidth}px;height:${document.documentElement.clientHeight}px;left:0;z-index:100000;pointer-events:none;background:url('${can.toDataURL("image/png")}') left top repeat`div.setAttribute("style", styleStr)// div.style.width = document.documentElement.clientWidth + 'px';// div.style.height = document.documentElement.clientHeight + 'px';document.body.appendChild(div)//此方法是防止用户通过控制台修改样式去除水印效果/* MutationObserver 是一个可以监听DOM结构变化的接口。 */// const observer = new MutationObserver(() => {//   const wmInstance = document.getElementById(id)//   if (//     (wmInstance && wmInstance.getAttribute("style") !== styleStr) ||//     !wmInstance//   ) {//     //如果标签在,只修改了属性,重新赋值属性//     // console.log("水印属性修改了")//     if (wmInstance) {//       // 避免一直触发//       observer.disconnect();//       console.log("水印属性修改了")//       wmInstance.setAttribute("style", styleStr)//     } else {//       /* 此处根据用户登录状态,判断是否终止监听,避免用户退出后登录页面仍然有水印 *///       if (store.state.user.token) {//         //标签被移除,重新添加标签//         // console.log('水印标签被移除了');//         document.body.appendChild(div)//       } else {//         observer.disconnect()//       }//     }//   }// })// observer.observe(document.body, {//   attributes: true,//   subtree: true,//   childList: true,// })return id;
}// 该方法只允许调用一次
watermark.set = (str, srt1, srt2, srt3) => {let id = setWatermark(str, srt1, srt2, srt3)setInterval(() => {if (document.getElementById(id) === null) {id = setWatermark(str, srt1, srt2, srt3)}}, 500)window.onresize = () => {setWatermark(str, srt1, srt2, srt3)}
}
// 移除
const outWatermark = id => {if (document.getElementById(id) !== null) {const div = document.getElementById(id)div.style.display = "none"}
}watermark.remove = () => {const str = iddoutWatermark(str)
}// 将 watermark 的控制方法挂载到 window 对象上
window.watermark = watermarkexport default watermark

上面的代码,很多人都写过,这里实现的也是大致效果,原理简单来讲就是:创建一个canvas,画一个客户端高x客户端宽的画布,里面画满水印,并将其的层级z-index设置最高,使其一直显示在界面的最上方,水印的效果就根据业务需求来调整。

这里将水印的控制方法(set和remove)都挂载在了window上,那么不论在哪个页面使用都可以直接调window来操作水印,水印的传参设置了四个str,其实可以根据实际情况添加更多,定制各样的效果。

2.防止用户通过控制台修改样式去除水印效果(可跳过,有弊端)

这里就是指上面代码里注释的的功能,可根据需求添加。

这个功能的原理:

  1. 创建了一个 MutationObserver 实例,(MutationObserver 允许开发人员监视 DOM 树的变化,并在发生变化时执行相应的操作),通过传一个制定ID的元素,将其存储在 wmInstance 变量中。
  2. 然后检查wmInstance 是否存在,及其style属性是否与指定的styleStr 变量相匹配,来判断水印是否需要更新。
  3. 如果 wmInstance 存在且其 style 属性不匹配,或者 wmInstance 不存在,则进行相应的处理:
    (1)如果 wmInstance 存在,则更新其 style 属性为 styleStr
    (2)如果 wmInstance 不存在,则检查用户登录状态。如果用户已登录(假设通过 store.state.user.token 判断),则向页面添加新的水印元素(假设该元素已在其他地方定义)。否则,断开 observer 的监听。
  4. 最后,调用 observer.observe() 方法开始观察文档主体的变化。选项对象指定了要观察的变化类型,包括 attributessubtreechildList

MutationObserver是什么?

MutationObserver 是 Web API 中的一部分,用于监视 DOM(文档对象模型)树的变化。它允许开发人员异步地观察文档中的节点并对其进行相应的处理。

在 Web 开发中,DOM 是指用于表示文档结构的树形数据结构,它由节点(node)组成,每个节点代表文档中的不同部分,如元素、属性、文本等。DOM 的结构和内容可能在页面加载后发生变化,比如用户的交互行为、脚本操作等都可能导致 DOM 发生变化。

MutationObserver 提供了一种机制,让开发人员可以监视 DOM 树的这些变化,并在变化发生时执行回调函数。这使得开发人员可以更灵活地响应 DOM 变化,而不必通过定时器或事件监听器等方式来轮询检查 DOM。

使用 MutationObserver,开发人员可以监视以下类型的 DOM 变化:

  1. 属性的改变(例如,元素的属性值发生变化)。
  2. 节点的添加或删除(例如,元素被插入或从 DOM 中移除)。
  3. 子节点的改变(例如,元素的子节点被添加或移除)。

通过 MutationObserver,开发人员可以更有效地监视 DOM 变化,从而实现更灵活、高效的 DOM 操作和交互。这在诸如单页面应用(SPA)等需要动态更新页面内容的场景中特别有用。

 (上述查自网络)

这个功能的弊端是, 如下图所示,如果浏览器修改窗口大小,也会触发水印的修改,并且水印的覆盖会带来一定视觉上的“卡顿”,实际使用中可能卡顿不是那么明显,但是这种情况也是值得考虑的。

3.水印的使用

使用的方式,有两种,局部使用和全局使用,就类似于我们引入UI组件库的组件一样,封装的水印js也需要局部或者全局注册。

(1)单页面/全局使用

这里就比较简单,我们在需要加水印的页面,引入水印,然后可以在mounted生命周期里调用它就行了。

import Watermark from "@/utils/watermark"mounted() {if (!Watermark) {Watermark = null// console.log("无水印",Watermark)return} else {Watermark.set('第一行','第二行','第三行','第二行')}},

如果是 全局使用,就在app.vue的页面里,根据当前页面的路径或其他标识来判断是否需要添加水印。

(2)全局使用+个别页面去掉

这个有多种实现方式,需要考虑业务场景,我这里推荐借助路由守卫,在router的路由守卫拦截的时候进行水印的set或者remove操作,如下:

router.afterEach((to) => {let Watermark= window.watermarkif(!Watermark ){Watermark=null// console.log(store.state.app.watermark,"store.state.app.watermark");return}if (to.fullPath === "/login" || to.fullPath === "/test") {Watermark.remove()} else {Watermark.set('第一行','第二行','第三行','第二行')}
})

使用路由守卫进行拦截的优点是:

路由守卫可以针对每个路由进行拦截,并判断是否需要添加水印,如果在特定路由不需要添加水印,可以在路由拦截时不调用水印脚本(或者remove),对水印添加的控制更加精细。


四、总结

在水印的实现里,第二种情况,我推荐结合两者的方法可以更好地满足不同场景下的需求,即在 app.vue中判断大部分页面是否需要添加水印,然后在路由守卫中针对个别页面进行额外的控制,这样页面就能满足大部分场景的要求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/708048.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

绘制窗口及窗口位置变化

为了方便窗口的移动 ,及相交窗口关闭之后被遮挡窗口的重绘,因此给每个窗口建立一个内存BUF,等到不涉及内容变更的重绘,只需要将该BUF复制到显存之中。 然而,重绘时存在一个被遮挡时如何操作的问题。比如下图中依次为从…

【QT+JS】QT和JS 中的正则表达式 、QT跑JS语言

【QTJS】QT和JS 中的正则表达式 、QT跑JS语言 前言正则表达式QT 中的使用QRegExp自带的cap方法怎么用?QRegExp的非贪婪模式与贪婪模式 JS 中的使用 QT 跑JS 语言 前言 在看大佬的系统代码时候,对其中灵活用到的正则表达式和QT 跑JS 语言部分感觉很陌生&…

iOS App冷启动优化:二进制重排

原理 二进制文件中方法的加载顺序, 取决于方法在代码文件中的书写顺序,而不是调用顺序。 应用程序启动时会调用到的方法是有限的,但可能分散在很多个。 由于内存是分页管理的,要加载就要 整页加载。 这就导致很多完全还用不到的方…

网站添加pwa操作和配置manifest.json后,没有效果排查问题

pwa技术官网:https://web.dev/learn/pwa 应用清单manifest.json文件字段说明:https://web.dev/articles/add-manifest?hlzh-cn Web App Manifest:Web App Manifest | MDN 当网站添加了manifest.json文件后,也引入到html中了&a…

FPGA-FIF0模型与应用场景(IP核)

什么是FIFO FIFO (First In First Out) ,也就是先进先出。FPGA或者ASIC中使用到的FIFO一般指的是对数据的存储具有先进先出特性的一个缓存器,常被用于数据的缓存或者高速异步数据的交互。它与普通存储器的区别是没有外部读写地址线,这样使用起来相对简单,但缺点就是只能顺序写…

python脚本实现全景站点欧拉角转矩阵

效果 脚本 import numpy as np import math import csv import os from settings import *def euler_to_rotation_matrix(roll, pitch, yaw):# 计算旋转矩阵# Z-Y-X转换顺序Rz

java多线程编程(学习笔记)入门

一、多线程创建的三种方式 (1)通过继承Thread本身 (2)通过实现runnable接口 (3)通过 Callable 和 Future 创建线程 其中,前两种不能获取到编程的结果,第三种能获取到结果 二、常见的成员方法 方法名称说明String getName()返回此线程的名称void setNam…

Docker之数据卷自定义镜像

文章目录 前言一、数据卷二、自定义镜像 前言 Docker提供了一个持久化存储数据的机制,与容器生命周期分离,从而带来一系列好处: 总的来说Docker 数据卷提供了一种灵活、持久、可共享的存储机制,使得容器化应用在数据管理方面更加…

Git 指令深入浅出【3】—— 远程仓库

Git 指令深入浅出【3】—— 远程仓库 一、远程仓库(一)基本指令1. 配置 SSH 密钥2. 推送远程仓库其他分支推送远程仓库方法1方法2建立分支链接 方法3 3. 合并分支请求 (二).gitignore 忽略文件(三)标签管理…

MVCC【重点】

参考链接 [1] https://www.bilibili.com/video/BV1YD4y1J7Qq/?spm_id_from333.1007.top_right_bar_window_history.content.click&vd_source0cb0c5881f5c7d76e7580fbd2f551074 [2]https://www.cnblogs.com/jelly12345/p/14889331.html [3]https://xiaolincoding.com/mysql…

基于频率增强的数据增广的视觉语言导航方法(VLN论文阅读)

基于频率增强的数据增广的视觉语言导航方法(VLN论文阅读) 本文提出的方法很简单,将原始图像增加其他随机图像的高频信息,得到增强的图像作为新的样本,与原始的样本交替训练。背后的动机是,vln模型对高频信息…

TV-SAM 新型零样本医学图像分割算法:GPT-4语言处理 + GLIP视觉理解 + SAM分割技术

TV-SAM 新型零样本医学图像分割算法:GPT-4语言处理 GLIP视觉理解 SAM分割技术 提出背景TV-SAM 方法论 提出背景 论文:https://arxiv.org/ftp/arxiv/papers/2402/2402.15759.pdf 代码:https://github.com/JZK00/TV-SAM 利用了GPT-4的强大语…

TCP/IP-常用网络协议自定义结构体

1、TCP/IP模型: 2、TCP/IP- 各层级网络协议(从下往上): 1)数据链路层: ARP: 地址解析协议,用IP地址获取MAC地址的协议,通过ip的地址获取mac地 …

【最新】如何将idea上的项目推送到gitee

1.打开Gitee,在首页,点击“”,创建一个仓库 2.填写仓库基本信息 3.下拉,点击“创建”,出现下方页面,证明仓库创建成功。 4.打开idea,下载gitee的插件(此处默认已经下载git&#xff0…

基于React, Redux实现的俄罗斯方块游戏及源码

分享一个俄罗斯方块游戏游戏框架使用的是 React Redux,其中再加入了 Immutable,用它的实例来做来Redux的state。(有关React和Redux的介绍可以看 安装 npm install运行 npm start浏览自动打开 http://127.0.0.1:8080/ 打包编译 npm run …

T - SQL使用事务 及 在Winform使用事务

事务适用场景 1 事务使用在存储过程中,直接在数据库中进行编写 2 事务使用在Winfrom项目中 SQl:使用事务转账操作的实例 一般都会找一个变量记录错误的个数,error记录上一句sql的错误和错误编号 declare errornum int 0 -- 定义…

selenium-激活pycharm,以及在pycharm中使用selenium时标红报错问题处理

激活pycharm:http://idea.955code.com/ 01 pycharm中导入selenium报错 现象: pycharm中输入from selenium import webdriver, selenium标红 原因1: pycharm使用的虚拟环境中没有安装selenium: 解决方法: 在pycharm中通过设置或terminal面板重新安装s…

nosql的注入

一、SQL注入数据库分类 关系型数据库 mysql oracle sqlserver 非关系型数据库 key-value redis MongoDB(not only sql) 二、MongoDB环境搭建 自己官网下载 Download MongoDB Community Server | MongoDB 其中Mongod.exe是它的一个启动 加上数据库&…

本届挑战赛亚军方案:面向微服务架构系统中无标注、多模态运维数据的异常检测、根因定位与可解释性分析

CheerX团队来自于南瑞研究院系统平台研发中心,中心主要从事NUSP电力自动化通用软件平台的关键技术研究与软件研发。 选题分析 图1 研究现状 本次CheerX团队的选题紧密贴合了目前的运维现状。实际运维中存在多种问题导致运维系统的不可用。比如故障发生时&#xff…

[设计模式Java实现附plantuml源码~行为型] 对象状态及其转换——状态模式

前言: 为什么之前写过Golang 版的设计模式,还在重新写Java 版? 答:因为对于我而言,当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言,更适合用于学习设计模式。 为什么类图要附上uml 因为很…