关于JS前端实现水印的代码操作
作者:十串
这篇文章主要介绍了关于JS前端实现水印的代码操作,文中给出了详细的实现思路和代码示例供大家参考,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
网页水印
实现思路
- 通过canvas生成一张水印图片
- 通过css将图片设置为目标节点的背景图
- 通过MutationObserver监听目标节点的类名变化,防止水印被删除
代码操作
- 通过canvas生成一张水印图片
function createImgBase(options) { const { content, width, height } = options; const canvasDom = document.createElement("canvas"); let ctx = canvasDom.getContext("2d"); canvasDom.width = width; canvasDom.height = height; if (ctx) { // 设置画笔的方向 ctx.rotate((-14 * Math.PI) / 180); // 设置水印样式 ctx.fillStyle = "rgba(100,100,100,0.4)"; ctx.font = "italic 20px Arial"; // 渲染水印 content.forEach((text, index) => { ctx.fillText(text, 10, 30 * (index + 1)); // 纵向拉开30的间距 }); } // document.body.appendChild(canvasDom); // 将canvas转为图片 return canvasDom.toDataURL("image/png"); } // createImgBase({ // content: ["介四嘛呀", "介四sui印", "内部机密材料", "严禁外泄!"], // width: 200, // height: 200, // });
- 将水印设置为目标节点的背景图片
function getWaterMark({ content, className, canvasHeight = 140, canvasWidth = 150, }) { // 生成图片 const data_url = createImgBase({ content, width: canvasWidth, height: canvasHeight, }); // 通过设置伪元素样式,添加水印图片为背景图 const defaultStyle = ` .${className} { position: relative; } .${className}::after { content: ""; background-image: url(${data_url}); display: block; position: absolute; top: 0; bottom: 0; left: 0; right: 0; pointer-events: none; }`; const styleDom = document.createElement("style"); styleDom.innerHTML = defaultStyle; document.head.appendChild(styleDom); } // getWaterMark({ // content: ["介四嘛呀", "介四sui印", "内部机密材料", "严禁外泄!"], // className: "content", // });
- 添加mutationObserver监听节点的变化
function listenerDOMChange(className) { // 获取要监听的节点 const targetNode = document.querySelector(`.${className}`); // 创建监听器 const observer = new MutationObserver(mutationList => { // 遍历变化记录 for (let mutationRecord of mutationList) { // 如果目标节点的class属性发生变化,判断是不是类名被删了,是的话把类名加回去 if (mutationRecord.attributeName === "class") { if(!Array.from(targetNode.classList).includes(className)) { targetNode.classList.add(className) } } } }); // 启动监听 observer.observe(targetNode, { attributes: true, }); } function getWaterMark({ content, className, canvasHeight = 140, canvasWidth = 150, }) { // 监听 listenerDOMChange(className); const data_url = createImgBase({ content, width: canvasWidth, height: canvasHeight, }); // ... const styleDom = document.createElement("style"); styleDom.innerHTML = defaultStyle; document.head.appendChild(styleDom); }
关于MutationObserver
MutationObserver 用来监听DOM的变化,DOM的增删、DOM属性的变化,子结点和文本内容的变化,都可以被监听。
MutationObserver 的监听和事件不同,事件是同步的,DOM的变化会立即触发对应的事件,而 MutationObserver 是异步的,会在下一个微任务执行时触发监听回调。
- 创建MutationObserver
const observer = new MutationObserver((mutationsList, observer) => { // mutationsList mutationRecord数组 记录了DOM的变化 // observer MutationObserver的实例 // 监听回调 console.log(mutationsList, observer); }) mutationObserver.observe(document.documentElement, { attributes: true, characterData: true, childList: true, subtree: true, attributeOldValue: true, characterDataOldValue: true });
- 开启监听
// node 监听的节点 // config 监听配置(要监听哪些内容) // observer.observe(node, config); mutationObserver.observe(document.documentElement, { attributes: true, // 属性变化 attributeOldValue: true, // 观察attributes变动时,是否需要记录变动前的属性值 attributeFilter: [‘class',‘src'] // 需要观察的特定属性 characterData: true, // 节点内容、文本的变化 characterDataOldValue: true, // 观察characterData变动时,是否需要记录变动前的属性值 childList: true, // 子结点变化 subtree: true, // 所有后代节点 }); // 停止监听 mutationObserver.disconnect() // 清除变动记录 mutationObserver.takeRecords()
图片水印
实现思路
方案一:通过oss添加水印 方案二:通过canvas生成带有水印的图片
oss实现
oss方式不做过多描述了 简单来说就是通过在获取图片时,在图片链接上增加参数,让oss生成一张带水印的图片。 注意点:
png图片的透明区域无法被添加水印。 解决方式: 可通过添加参数的方式,让oss将图片转为jpg格式(jpg格式会对透明区域做颜色填充)。
字体大小写为定值,原图大小会影响到水印字体的显示大小。 解决方式:通过创建img标签,onLoad获取图片后,根据图片宽高计算合适的字体大小,然后再一次获取带水印的图片。
用户通过删除参数的方式可以删除水印 解决方式:设置oss的安全级别,不带水印不可访问。
canvas实现
- 将img转为canvas
async function imgToCanvas(cav, imgSrc) { const img = new Image(); img.src = imgSrc; // 防止因跨域导致的图片加载失败(该方法有局限性) img.setAttribute("crossOrigin", "anonymous"); // 等待图片加载 await new Promise(resolve => (img.onload = resolve)); cav.width = img.width; cav.height = img.height; const ctx = cav.getContext("2d"); if (ctx) { ctx.drawImage(img, 0, 0); } return cav; }
- 添加水印
function addWaterMask(cav, content) { const ctx = cav.getContext("2d"); ctx.fillStyle = "rgba(100,100,100,0.2)"; ctx.font = `24px serif`; ctx.translate(0, 0); ctx.rotate((5 * Math.PI) / 180); // 生成水印 let x = 0, y = 0; while (x < cav.width) { y = 0; while (y < cav.height) { ctx.fillText(content, x, y); y += 100; } x += 150; } }
- 使用
(async function () { const canvas = document.createElement("canvas"); await imgToCanvas( canvas, "https://pp.myapp.com/ma_pic2/0/shot_54360764_1_1716462139/0" ); addWaterMask(canvas, "介四sui印"); // document.body.appendChild(canvas); return canvas.toDataUrl("image/png") })();
到此这篇关于关于JS前端实现水印的代码操作的文章就介绍到这了,更多相关JS实现水印内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!