方案
1.生成重复元素
把水印容器元素position:fixed,覆盖到需要打水印的区域,区域里面重复生成水印元素,设置透明度。设置pointer-events: none; 点击穿透功能。
主要用到 document的元素操作api。
2.设置背景图片
在上一种方法的基础上,把元素去掉,把水印容器元素的背景图片设置为水印。图片可以用canvas生成。
3.MutationObserver 优化
MutationObserver监听dom树更改,当我们调试删除元素、修改样式时可触发。重新生成水印即可。用vue2自定义指令封装水印,全部代码如下。
const globalCanvas = null
const globalWaterMark = null
// watermark 样式
let style = `
display: block;
overflow: hidden;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-repeat: repeat;
pointer-events: none;`
const getDataUrl = ({
font,
fillStyle,
textAlign,
textBaseline,
text
}) => {
font = font || '16px normal'
fillStyle = fillStyle || 'rgba(180, 180, 180, 0.2)'
text = text || ''
const rotate = -20
const canvas = globalCanvas || document.createElement('canvas')
const ctx = canvas.getContext('2d') // 获取画布上下文
ctx.rotate((rotate * Math.PI) / 180)
ctx.font = font
ctx.fillStyle = fillStyle
ctx.textAlign = textAlign || 'left'
ctx.textBaseline = textBaseline || 'middle'
ctx.fillText(text, canvas.width / 10, canvas.height / 2)
return canvas.toDataURL('image/png')
}
const setWaterMark = (el, binding) => {
const parentElement = el.parentElement
// 获取对应的 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, binding) => {
const waterMarkEl = el.parentElement.querySelector('.water-mark')
const observer = new MutationObserver((mutationsList) => {
if (mutationsList.length) {
const { removedNodes, type, target } = mutationsList[0]
const currStyle = waterMarkEl.getAttribute('style')
// 证明被删除了
if (removedNodes[0] === waterMarkEl) {
observer.disconnect()
init(el, { value: binding })
} else if (
type === 'attributes'
&& target === waterMarkEl
&& currStyle !== style
) {
waterMarkEl.setAttribute('style', style)
}
}
})
observer.observe(el.parentElement, {
childList: true,
attributes: true,
subtree: true
})
}
// 初始化
const init = (el, binding) => {
// 设置水印
setWaterMark(el, binding.value)
// 启动监控
createObserver(el, binding.value)
}
// 定义指令配置项
const directives = {
inserted(el, binding) {
init(el, binding)
}
}
export default {
name: 'watermark',
directives
}
其他
还有一种修改rgb值的水印方案,当然了,其他平台类似,还有各种方式去掉水印,现有的方案都不是完美的 debugger时,disable javascript不启用js,都可以去掉水印。
f12 及 鼠标右击处理
document.addEventListener('keydown', function(e) {
if (e.key === 'F12') {
e.preventDefault()
}
})
// 阻止菜单右键
document.addEventListener('contextmenu', function(event) {
event.preventDefault()
})
参考