前端基于 DOM 或者 Canvas 实现页面水印
前言
我们会看到很多页面带有水印,但是怎么实现呢?当然可以有多种实现方式,本文主要讲解在 vue 项目中基于 DOM 或者 Cavans 实现水印效果,当然还有其他的实现方式,比如在原图片的基础上加上水印生成新的图片,但是这需要后端处理。因为要在 vue 项目中使用,所以我使用自定义指令可以直接对挂载的 dom 实现水印效果。
本文实现水印的项目环境为:vue + vite + ts
一、vue 自定义指令 directive 讲解
前面专门有一篇讲解自定义指令 directive,可到我的主页查看自定义指令文章
二、基于 DOM 的实现方式
1. 思路整理
获取宽高(1)获取绑定元素的实际宽度 clientWidth(2)获取绑定元素实际高度 clientHeight(3)获取绑定元素的父元素 parentElement
创建盒子(1)创建一个包裹水印图片的盒子(2)创建一个水印图片的盒子
设置盒子样式(1)包裹水印盒子宽高为绑定元素的宽高,即 clientWidth、clientHeight(2)水印盒子设置背景图、旋转度、宽高、点击穿透
设置创建的元素的位置(1)水印盒子放到包裹水印图片的盒子里 (包裹水印图片的盒子包裹水印)(2)包裹水印图片的盒子放到被绑定元素之前(3)被绑定元素放到裹水印图片的盒子里(不然被绑定元素与包裹水印图片的盒子层级同级)
2.新建 index.vue
将水印的指令放到标签上,设置标签的宽高。水印可以放大div
标签上,也可以是img
标签上。注意:img
才有onload
方法,div
标签么有。
3. 新建directives
文件
在directives
文件下创建waterMark.ts
文件,具体内容实现如下:
4. 在directives
文件下创建 index.ts
文件
5. 在main.ts
中全局引入
6. 缺点
直接删除水印元素时,页面中的水印直接就被删除了,当然我们可以用
MutationObserver
对水印元素进行监听,删除时,我们再立即生成一个水印元素就可以了,具体方面在下面讲解。如果原始元素本身存在 css 定位等规则,会导致整体布局效果出现影响,因为上面实现排除了原始元素没有定位,所以实现方式不是很严谨,本文具体实现实现如下:
创建一个水印的容器设置为
position:relative
将原有的节点放入到这个容器中
同时创建一个带有水印的 dom 设置为
position:absolute
,实现这个水印元素覆盖到原始元素的上层,以实现水印的效果。
三、基于 Canvas 和 MutationObserver 的实现方式
1. 思路整理
配置水印的具体样式(大小,旋转角度,文字填充)
设置水印(位置)
监听 dom 变化(防止水印删除后页面不再展示水印)
2. 生成水印
通过将图片绘制在cavans
中,然后通过cavans
的toDataURL
方法,将图片转为 base64 编码。
3. 使用 MutationObserver 监听水印
使用MutationObserver
监听 dom 变化,MutationObserver
详细用法之前已经讲过了,详细可见作为前端你还不懂MutationObserver?那Out了具体监听逻辑如下:
1.直接删除 dom(1)先获取设置水印的 dom(2)监听到被删除元素的 dom(3)如果他两相等的话就停止观察,初始化(设置水印+启动监控)
2.删除 style 中的属性(1)判断删除的是否是标签的属性 (type === "attributes")(2)判断删除的标签属性是否是在设置水印的标签上(3)判断修改过的 style 和之前的 style 对比,不等的话,重新赋值
四、成果展示
删除水印标签依然还在,除非删除水印注册的标签才能删除水印,但是这样做毫无意义,因为这样做内容也会全部删除掉。
附:文中用到的 js 基础知识
toDataURL 用法
toDataURL(type, encoderOptions)
,接收两个参数:
type:图片类型,比如
image/png、image/jpeg、image/webp
等等,默认为image/png
格式encoderOptions:图片质量的取值范围(0-1),默认值为 0.92,当超出界限按默认值 0.92
版权声明: 本文为 InfoQ 作者【不叫猫先生】的原创文章。
原文链接:【http://xie.infoq.cn/article/6cfd9222a7bb26018b4fbf5af】。文章转载请联系作者。
评论