首页IT科技html页面制作(前端基于DOM或者Canvas实现页面水印)

html页面制作(前端基于DOM或者Canvas实现页面水印)

时间2025-05-05 23:40:40分类IT科技浏览3342
导读:🐱 个人主页:不叫猫先生...

🐱 个人主页:不叫猫先生

🙋‍♂️ 作者简介:前端领域新星创作者           、阿里云专家博主           ,专注于前端各领域技术                 ,共同学习共同进步      ,一起加油呀!

💫系列专栏:vue3从入门到精通                 、TypeScript从入门到实践

📢 资料领取:前端进阶资料以及文中源码可以找我免费领取

🔥 前端学习交流:博主建立了一个前端交流群     ,汇集了各路大神                 ,一起交流学习           ,期待你的加入!(文末有我wx或者私信)

前言

我们会看到很多页面带有水印     ,但是怎么实现呢?当然可以有多种实现方式                 ,本文主要讲解在vue项目中基于DOM或者Cavans实现水印效果           ,当然还有其他的实现方式,比如在原图片的基础上加上水印生成新的图片                 ,但是这需要后端处理           。因为要在vue项目中使用                 ,所以我使用自定义指令可以直接对挂载的dom实现水印效果                 。

本文实现水印的项目环境为:vue + vite + ts

一      、vue自定义指令directive讲解

前面专门有一篇讲解vue2.x与vue3.x中自定义指令详解

二     、基于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标签么有                 。

<script setup lang="ts"> import { ref } from "vue"; </script> <template> <div class="index-content" > <div class="watermaker" v-watermark ></div> <!-- <img v-watermark style="width:400px;height:400px" src="../assets/vue.svg" alt=""> --> </div> </template> <style scoped> .watermaker { width: 400px; height: 400px; } .index-content{ width: 100%; height: 100%; } </style>

3. 新建directives文件

在directives文件下创建waterMark.ts 文件           ,具体内容实现如下:

import waterImg from "@/assets/vue.svg" const directives: any = { mounted(el: HTMLElement) { //如果el元素是img                 ,则可以用el.onload将下面包裹 const { clientWidth, clientHeight, parentElement } = el; console.log(parentElement, parentElement) const waterMark: HTMLElement = document.createElement(div); const waterBg: HTMLElement = document.createElement(div); //设置waterMark的class和style waterMark.className = `water-mark`; waterMark.setAttribute(style, ` display: inline-block; overflow: hidden; position: relative; width: ${clientWidth}px; height: ${clientHeight}px;`); // 创建waterBg的class和style waterBg.className = `water-mark-bg`;// 方便自定义展示结果 waterBg.setAttribute(style, ` position: absolute; pointer-events: none;`在这里插入代码片` transform: rotate(45deg); width: 100%; height: 100%; opacity: 0.2; background-image: url(${waterImg}); background-repeat: repeat; `); // 水印元素waterBg放到waterMark元素中 waterMark.appendChild(waterBg); //waterMark插入到el之前      ,即插入到绑定元素之前 parentElement?.insertBefore(waterMark, el); // 绑定元素移入到包裹水印的盒子 waterMark.appendChild(el); } } export default { name: watermark, directives }

4. 在directives文件下创建 index.ts文件

import type { App } from vue import watermark from ./waterMark export default function installDirective(app: App) { app.directive(watermark.name, watermark.directives); }

5. 在main.ts中全局引入

import { createApp } from vue import App from ./App.vue import directives from ./directives const app = createApp(App); app.use(directives); app.mount(#app);

6. 缺点

直接删除水印元素时     ,页面中的水印直接就被删除了                 ,当然我们可以用MutationObserver对水印元素进行监听           ,删除时     ,我们再立即生成一个水印元素就可以了                 ,具体方面在下面讲解           。 如果原始元素本身存在 css 定位等规则           ,会导致整体布局效果出现影响,因为上面实现排除了原始元素没有定位                 ,所以实现方式不是很严谨                 ,本文具体实现实现如下: 创建一个水印的容器设置为 position:relative 将原有的节点放入到这个容器中 同时创建一个带有水印的 dom 设置为position:absolute ,实现这个水印元素覆盖到原始元素的上层           ,以实现水印的效果     。

三           、基于Canvas和MutationObserver的实现方式

1. 思路整理

配置水印的具体样式(大小                 ,旋转角度      ,文字填充) 设置水印(位置) 监听dom变化(防止水印删除后页面不再展示水印)

2. 生成水印

通过将图片绘制在cavans中           ,然后通过cavans的toDataURL方法                 ,将图片转为base64编码                 。

// 全局保存 canvas 和 div       ,避免重复创建(单例模式) const globalCanvas = null; const globalWaterMark = null; // 获取 toDataURL 的结果 const getDataUrl = ( // font = "16px normal", // fillStyle = "rgba(180, 180, 180, 0.3)", // textAlign, // textBaseline, // text = "请勿外传", ) => { const rotate = -10; const canvas = globalCanvas || document.createElement("canvas"); const ctx = canvas.getContext("2d"); // 获取画布上下文 ctx.rotate((rotate * Math.PI) / 180); ctx.font = "16px normal"; ctx.fillStyle = "rgba(180, 180, 180, 0.3)"; ctx.textAlign = "left"; ctx.textBaseline = "middle"; ctx.fillText(请勿外传, canvas.width / 3, canvas.height / 2); return canvas.toDataURL("image/png"); };

3. 使用MutationObserver监听水印

使用MutationObserver监听dom变化     ,MutationObserver详细用法之前已经讲过了                 ,详细可见作为前端你还不懂MutationObserver?那Out了 具体监听逻辑如下:

1.直接删除dom

(1)先获取设置水印的dom

(2)监听到被删除元素的dom

(3)如果他两相等的话就停止观察           ,初始化(设置水印+启动监控) 2.删除style中的属性

(1)判断删除的是否是标签的属性 (type === “attributes           ”)

(2)判断删除的标签属性是否是在设置水印的标签上

(3)判断修改过的style和之前的style对比     ,不等的话                 ,重新赋值 // watermark 样式 let style = ` display: block; overflow: hidden; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-repeat: repeat; pointer-events: none;`; //设置水印 const setWaterMark = (el: HTMLElement, binding: any) => { const { parentElement } = el; // 获取对应的 canvas 画布相关的 base64 url const url = getDataUrl(binding); // 创建 waterMark 父元素 const waterMark = globalWaterMark || document.createElement("div"); waterMark.className = `water-mark`; // 方便自定义展示结果 style = `${style}background-image: url(${url});`; waterMark.setAttribute("style", style); // 将对应图片的父容器作为定位元素 parentElement.setAttribute("style", "position: relative;"); // 将图片元素移动到 waterMark 中 parentElement.appendChild(waterMark); }; // 监听 DOM 变化 const createObserver = (el: HTMLElement, binding: any) => { console.log(el, el) console.log(style, style) // console.log(el.parentElement.querySelector(.water-mark),el.parentElement) const waterMarkEl = el.parentElement.querySelector(".water-mark"); const observer = new MutationObserver((mutationsList) => { console.log(mutationsList, mutationsList) if (mutationsList.length) { const { removedNodes, type, target } = mutationsList[0]; const currStyle = waterMarkEl.getAttribute("style"); // console.log(currStyle, currStyle) // 证明被删除了 // (1)直接删除dom // 1.先获取设置水印的dom // 2.监听到被删除元素的dom // 如果他两相等的话就停止观察           ,初始化(设置水印+启动监控) // (2) 删除style中的属性 // 1 判断删除的是否是标签的属性 (type === "attributes") // 2.判断删除的标签属性是否是在设置水印的标签上 // 3.判断修改过的style和之前的style对比,不等的话                 ,重新赋值 if (removedNodes[0] === waterMarkEl) { console.log(removedNodes[0]) // 停止观察           。调用该方法后                 ,DOM 再发生变动,也不会触发观察器。 observer.disconnect(); //初始化(设置水印           ,启动监控) init(el, binding); } else if ( type === "attributes" && target === waterMarkEl && currStyle !== style ) { console.log(currStyle, currStyle) console.log(style, style) waterMarkEl.setAttribute("style", style); } } }); observer.observe(el.parentElement, { childList: true, attributes: true, subtree: true, }); }; // 初始化 const init = (el: HTMLElement, binding: any = {}) => { // 设置水印 setWaterMark(el, binding.value); // 启动监控 createObserver(el, binding.value); }; const directives: any = { mounted(el: HTMLElement, binding: any) { //注意img有onload的方法                 ,如果自定义指令注册在html标签的话      ,只需要init(el, binding.value) el.onload = init.bind(null, el, binding.value); }, };

四、成果展示

删除水印标签依然还在           ,除非删除水印注册的标签才能删除水印                 ,但是这样做毫无意义      ,因为这样做内容也会全部删除掉                 。

附:文中用到的js基础知识

toDataURL用法

toDataURL(type, encoderOptions)     ,接收两个参数:

type:图片类型                 ,比如image/png                 、image/jpeg                 、image/webp等等           ,默认为image/png格式 encoderOptions:图片质量的取值范围(0-1)     ,默认值为0.92                 ,当超出界限按默认值0.92
声明:本站所有文章           ,如无特殊说明或标注,均为本站原创发布                 。任何个人或组织                 ,在未征得本站同意时                 ,禁止复制、盗用           、采集                 、发布本站内容到任何网站      、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理           。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
网站首页的图片怎么更换颜色(怎么更改网站首页图片)