使用mutationObserver检测DOM变化

658 字
3 分钟
使用mutationObserver检测DOM变化

最近在写项目时,有一个需求是保存的同时截取当前页面内容并生成缩略图,下面是我的实现过程。

生成快照#

  • 将DOM转成图片的三种方式 dom-to-imagehtml2canvas html-to-image 对比之后选择html2canvas

  • 使用

    async function eleToImage(content) {
    const container = document.createElement('div');
    container.style.position = 'absolute';
    container.style.left = '-9999px';
    container.innerHTML = typeof content === 'string' ? content : content?.outerHTML;
    document.body.appendChild(container);
    /* 删除transform布局,改为position */
    var transformLay = container.querySelectorAll('.react-grid-item');
    let list = Array.prototype.slice.call(transformLay || [])
    list.forEach((item) => {
    let positon = item.style.transform.slice(10, -1).split(',');
    item.style.left = positon[0]
    item.style.top = positon[1]
    item.style.transform = ''
    })
    var textDom = container.querySelectorAll('.text');
    let textList = Array.prototype.slice.call(textDom || [])
    textList.forEach((item) => {
    // 截图时文字会突出
    item.style.fontSize = parseInt(item.style.fontSize) * 0.92 + 'px';
    })
    console.time('canvas')
    const blob = await new Promise<any>((resolve) => {
    html2canvas(container, { useCORS: true }).then((canvas) =>
    canvas.toBlob(resolve, 'png', 0.1)
    );
    });
    document.body.removeChild(container);
    console.timeEnd('canvas')
    return blob;
    }
  • 使用html2canvas时遇到的坑

    1. transform兼容性问题,html2canvas不支持transform,需要修改成position
    2. 字体限制宽度时,可能会遮挡,需要缩小一定比例
    3. 图片跨域问题,需要配置useCORS

通过html2canvas将DOM转成图片并保存,原则上已经解决了问题,但每次保存时不管页面有没有发生变化,都会生成快照,尝试通过MutationObserver解决一下。

优化#

为了通用,写了一个自定义hooks,通过传入func函数来监听DOM变化时的回调

import { useEffect } from 'react';
/**
* MutationObserver主要用于监视对DOM树所做的修改
* https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver
*/
const useMutationObserver = (dom, depends, func) => {
useEffect(() => {
let mutation: MutationObserver;
if(dom) {
// 当观察到变动时执行的回调函数
const callback = (mutations: MutationRecord[], observer: MutationObserver) => {
func(mutations, observer);
}
const config = {
attributes: true, // 观察属性变动
// attributeFilter: ['style', 'childList'],
attributeOldValue: true,
characterData: true, // 监听元素内的数据变动
characterDataOldValue: true,
childList: true, // 监听子元素数量变动(子元素的属性变化不会触发事件)(只针对一级子元素,孙子元素的数量变化不会触发事件)
subtree: true, // 将observer事件下发到目标元素的所有子元素,相当于对子元素也进行了observer
}
// 创建一个观察器实例并传入回调函数
mutation = new MutationObserver(callback);
// config 观察器的配置(需要观察什么变动)
// 在DOM更改时 开始接收通知
mutation.observe(dom, config);
}
// 组件销毁时 阻止MutationObaserver继续接收通知
return () => {
if(mutation) {
mutation.disconnect();
}
}
}, [depends])
}
export default useMutationObserver;
// 使用: 监测删除事件
// const isDelBtn = useRef<boolean>(false);
// const func = (mutations) => {
// // 如果删除最后一个空格 则将当前的优惠券删除
// if (
// mutations[0]?.removedNodes[0]?.className === "delete" &&
// !isDelBtn.current
// ) {
// const key = mutations[0]?.removedNodes[0].getAttribute("data-key");
// removeNode(key);
// }
// };
// useMutationObserver(refInput, func);
使用mutationObserver检测DOM变化
https://wangxiang.website/posts/工作/mutationobserver/
作者
翔子
发布于
2022-07-26
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
翔子
前端开发工程师
公告
博客已从 VitePress 迁移到 Astro + Firefly 主题,223 篇文章全部保留。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
221
分类
9
标签
28
总字数
411,914
运行时长
0
最后活动
0 天前

文章目录