当前位置: 首页 > news >正文

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中判断大部分页面是否需要添加水印,然后在路由守卫中针对个别页面进行额外的控制,这样页面就能满足大部分场景的要求。

相关文章:

vue实现水印功能

目录 一、应用场景 二、实现原理 三、详细开发 1.水印的实现方式 2.防止用户通过控制台修改样式去除水印效果(可跳过,有弊端) 3.水印的使用 (1)单页面/全局使用 (2)全局使用个别页面去掉…...

记录一下我的Ruby On Rails的systemd服务脚本

自己也是一个 ROR 框架的学习者,同时也是 Ruby 的新手。对于如何让 ROR 应用随系统自动启动并不是很了解。在尝试了各种方法之后,我最终找到了一条可行的途径。虽然不确定是否完全正确,但服务已经成功启动了。因此,我决定在这里保…...

【计算机网络】传输层——TCP和UDP详解

文章目录 一. TCP和UDP简介二. UDP 协议详解1. UDP报文格式2. UDP的使用场景 三. TCP 协议详解1. TCP报文格式2. TCP协议的重要机制确认应答(保证可靠传输的最核心机制)超时重传连接管理(三次握手、四次挥手)!&#xf…...

stm32和嵌入式linux可以同步学习吗?

在开始前我有一些资料,是我根据网友给的问题精心整理了一份「stm3的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!如果需要使用STM32,建…...

maven--->maven中的<properties>属性有什么作用?

🙌🙌🙌🙌🙌🙌 在Maven中,元素用于定义项目中可重用的属性值。这些属性值可以在项目的POM文件中被引用,以便在整个项目中统一管理和使用。通过使用元素,可以避免在POM文件…...

android 网络请求总结

1 先看下基础部分: android okhttp网络访问是基于 tcp/ip 的 最上层是应用层的封装,有http,https(加密),ftp 下面是socket套接字的封装,就是将ip和端口的封装 在下面就是tcp/udp 在下面 ip协议…...

用 Python 自动化处理无聊的事情

“编程最棒的部分就是看到机器做一些有用的事情而获得的胜利。用 Python 将无聊的事情自动化将所有编程视为这些小小的胜利;它让无聊变得有趣。” Hilary Mason,数据科学家兼 Fast Forward Labs 创始人 “我很享受打破东西然后把它们重新组合起来的乐趣…...

稀疏计算、彩票假说、MoE、SparseGPT

稀疏计算可能是未来10年内最有潜力的深度学习方向之一,稀疏计算模拟了对人脑的观察,人脑在处理信息的时候只有少数神经元在活动,多数神经元是不工作的。而稀疏计算的基本思想是:在计算过程中,将一些不重要的参数设置为…...

Git Windows安装教程

Git简介 Git是目前世界上最先进的分布式版本控制系统。它的工作原理 / 流程如下: [ Workspace:工作区 Index / Stage:暂存区 Repository:仓库区(或本地仓库) Remote:远程仓库 ] Git的下载 去 Git 官网下载对应系统的软件了,下…...

iOS高级理论:Runtime应用

一、遍历类的属性,快速归档 在 iOS 中,可以使用 Runtime 遍历类的属性来实现快速的归档(Archiving)操作。归档是将对象转换为数据流以便存储或传输的过程。下面是一个简单的示例,展示如何使用 Runtime 遍历类的属性进…...

php判断和过滤get或者post的html标签,防止跨站点脚本(XSS),链接注入,框架注入等攻击

大部分网站都包含搜索功能,根据用户搜索的词去执行服务端的业务逻辑。如果一些黑客在搜索参数包含链接(a)、嵌入其他网页(iframe)、前端代码(script)等html字符,再加上服务端php不加…...

PySide6实现课堂点名程序

目录 一:实现思路 二:实现代码 三:完整代码和界面 一:实现思路 为了创建一点名程序,并编写一个基本的 GUI 应用程序。新建一个窗口,展在窗口界面添加开始和停止按钮的QPushButton,和展示正在显示的人名QLabel,点击开始时随机显示人名列表中的一个名字并且展示在QLab…...

瑞_Redis_Redis命令

文章目录 1 Redis命令Redis数据结构Redis 的 key 的层级结构1.0 Redis通用命令1.0.1 KEYS1.0.2 DEL1.0.3 EXISTS1.0.4 EXPIRE1.0.5 TTL 1.1 String类型1.1.0 String类型的常见命令1.1.1 SET 和 GET1.1.2 MSET 和 MGET1.1.3 INCR和INCRBY和DECY1.1.4 SETNX1.1.5 SETEX 1.2 Hash类…...

js 算法题 在数组中找出和为目标值 target 的那 两个 整数,并返回它们的数组下标

题目:给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 你可以…...

基于springboot接口的编写

目录 1、模糊分页查询 2、批量删除 3、新增 4、编辑 此接口非彼接口。此接口是MVC的设计模式中的Controller层,一般我们会叫Controller层里的方法为接口。他们是负责接收前端或者其它服务的传来的请求,并对请求进行相应的处理,最终再将处…...

【HarmonyOS】鸿蒙开发之Video组件——第3.7章

Video组件内VideoOptions属性简介 src:设置视频地址。currentProgressRate:设置视频播放倍速,参数说明如下: number|string:只支持 0.75 , 1.0 , 1.25 , 1.75 , 2.0 。P…...

React引入css的几种方式以及应用

1.直接引入css文件 import "./parent.css" 2.引入css模块,定义文件名[组件名.module.css];该方式可避免类名的重复,每个组件都有独立的作用域,避免了全局污染,保证了类名的唯一性 import styles from &qu…...

[算法沉淀记录] 排序算法 —— 冒泡排序

排序算法 —— 冒泡排序 基本概念 冒泡排序是一种简单的排序算法。它重复地遍历要排序的列表,一次比较两个元素,并交换它们的位置,如果它们不是按照升序排列的。这步遍历是重复进行的,直到没有再需要交换,也就是说该…...

【机器人最短路径规划问题(栅格地图)】基于遗传算法求解

基于遗传算法求解机器人最短路径规划问题(栅格地图)的仿真结果 仿真结果: 路径长度的变化曲线: 遗传算法优化后的机器人避障路径:...

如何做代币分析:以 TRX 币为例

作者:lesleyfootprint.network 编译:cicifootprint.network 数据源:TRX 代币仪表板 (仅包括以太坊数据) 在加密货币和数字资产领域,代币分析起着至关重要的作用。代币分析指的是深入研究与代币相关的数据…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...

uniapp中使用aixos 报错

问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

企业如何增强终端安全?

在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...