如何防止水印被恶意删除或者隐藏?
继上篇 Vue3 实现网页背景水印功能 我们了解了常见的网页水印功能是如何实现的,懂原理的都知道水印是通过在网页中添加代码绘制 DOM 元素覆盖在原有的网页上而来的,一旦你打开浏览器中的元素审查,可以通过删除元素或者在元素的样式上操作属性值,就可以用来临时屏蔽水印。
为了防止作弊,我们可以利用接口 MutationObserver
对 DOM 元素进行监听。如果你对监听的元素进行样式属性的设置,或者对监听元素的子元素进行删除,都能通过 MutationObserver
的回调函数进行捕获,然后再针对你的修改操作进行复原。这样可以有效防止临时操作网页元素来隐藏水印。
MutationObserver 接口提供了监视对 DOM 树所做更改的能力。它被设计为旧的 Mutation Events 功能的替代品,该功能是 DOM3 Events 规范的一部分。
// 选择需要观察变动的节点 const targetNode = document.getElementById('some-id'); // 观察器的配置(需要观察什么变动) const config = { attributes: true, childList: true, subtree: true }; // 当观察到变动时执行的回调函数 const callback = function(mutationsList, observer) { // Use traditional 'for loops' for IE 11 for(let mutation of mutationsList) { if (mutation.type === 'childList') { console.log('A child node has been added or removed.'); } else if (mutation.type === 'attributes') { console.log('The ' + mutation.attributeName + ' attribute was modified.'); } } }; // 创建一个观察器实例并传入回调函数 const observer = new MutationObserver(callback); // 以上述配置开始观察目标节点 observer.observe(targetNode, config); // 之后,可停止观察 observer.disconnect();
了解如何使用之后,我们对上篇封装的增加水印功能的 hooks
进行优化,添加一个防删除的方法 antiDeletion
,里面对水印元素和它的父级也就是 body
进行了监听。
对父级元素进行监听,是为了捕获对它的删除操作,mutation
的类型为 childList
,当删除水印元素的时候,我们通过回调参数 removedNodes
拿到删除元素的内容后再往它的父节点动态插入水印元素,相当于未删除成功。
然后还需要防止用户对水印元素进行样式属性的设置,比如 display: none;
隐藏元素内容。这个时候我们添加对水印 DIV 层的监听,通过对 mutation
类型为attributes
的判断,然后强制给可能导致水印显示变化的样式进行复原操作。
const observers = []; function antiDeletion() { const targetNode = unref(watermarkEl); const parentNode = unref(appendEl); const config = { childList: true, attributes: true, attributeOldValue: true, characterData: true, characterDataOldValue: true }; observers[0] = new MutationObserver((mutationList, _observer) => { for (const mutation of mutationList) { const type = mutation.type; switch (type) { case "childList": console.log("childList", mutation); if (mutation.removedNodes.length > 0) { parentNode.appendChild(mutation.removedNodes[0]); } break; default: break; } } }); observers[0].observe(parentNode, { childList: true }); observers[1] = new MutationObserver((mutationList, _observer) => { for (const mutation of mutationList) { const type = mutation.type; switch (type) { case "attributes": console.log("attributes", mutation); if (mutation.attributeName === "style") { targetNode.style.display = "block"; targetNode.style.zIndex = "100000"; targetNode.style.top = "0px"; targetNode.style.left = "0px"; targetNode.style.position = "absolute"; } if (mutation.attributeName === "class") { targetNode.style.setProperty( "visibility", "visible", "important" ); } break; default: break; } } }); observers[1].observe(targetNode, config); }
参考文档:
https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver
谁来说两句
博主,交换友情链接吗?
你的网站是?