概述
MutationObserver 监听dom 的任何变化,比如子元素、属性和文本内容变化;异步触发,dom改变并不会马上触发,要等到当前DOM操作都结束才触发
实例化MutationObserver
const mutationObserverInit = {
childList: true, // 监听目标节点添加或删除新的子节点
subtree: true, // 将监视范围扩展至目标节点整个节点树中的所有节点
characterData: true, // 监视指定目标节点或子节点树中节点所包含字符数据的变化
attributeOldValue: true,
attributes: true, // 观察受监视元素的属性值变更
}
el.observer.observe(document.body,mutationObserverInit)
在vue中实战
// MutationObserver 监听dom 的任何变化,比如子元素、属性和文本内容变化
// 异步触发,dom改变并不会马上触发,要等到当前DOM操作都结束才触发
import type { Directive, App } from 'vue'
interface Value {
font: string
textColor: string
text: string
}
const waterMarkId = 'waterMark'
const canvasId = 'can'
const drawWaterMark = (el: HTMLElement, value: Value) => {
const {
font = '16px',
textColor = 'rgba(180, 180, 180, 0.3)',
text = '冷血出品',
} = value
const canvas = document.getElementById(canvasId) as HTMLCanvasElement
const can = canvas || document.createElement('canvas')
can.id = canvasId
el.appendChild(can)
can.width = 400
can.height = 200
can.style.display = 'none'
const ctx = can.getContext('2d') as CanvasRenderingContext2D
ctx?.rotate((-20 * Math.PI) / 180)
ctx.font = font
ctx.textAlign = 'left'
ctx.fillStyle = textColor
ctx.textBaseline = 'middle'
ctx.fillText(text, can.width / 3, can.height / 2)
const waterMaskDiv = document.createElement('div')
waterMaskDiv.id = waterMarkId
const styleStr = `
width: 100%;
height: 100%;
position: fixed;
z-index: -1;
top: 0;
left: 0;
pointer-events: none;
background-image: url(${can.toDataURL('image/png')})
`
waterMaskDiv.setAttribute('style', styleStr)
el.appendChild(waterMaskDiv)
return styleStr
}
const vWaterMark: Directive = {
mounted(el, { value }) {
if (!value) return
el.waterMarkStylestr = drawWaterMark(el, value)
el.observer = new MutationObserver(() => {
console.log('触发mutationObserver')
const instance = document.getElementById(waterMarkId)
const style = instance?.getAttribute('style')
const { waterMarkStylestr } = el
if ((instance && style !== waterMarkStylestr) || !instance) {
if (instance) {
instance.setAttribute('style', waterMarkStylestr)
} else {
drawWaterMark(el, value)
}
}
})
el.observer.observe(document.body, {
childList: true,
attributes: true,
subtree: true,
})
},
unmounted(el) {
// 元素删除时,停止监控
el.observer.disconnect()
el.observer = null
},
}
export default vWaterMark