You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

构建可优先运行的MutationObserver包装器用于浏览器扩展

概述

出于安全考量,此MutationObserver包装器应能为开发者提供DOM中发生的所有变更信息。

问题

我需要一种简便的方法来创建MutationObserver的包装器,希望在页面中创建MutationObserver时收到通知,同时确保该代码优先于其他所有代码运行,以便将其集成到浏览器扩展中。

尝试代码
const dump = console.log.bind(console);

class Observer
{
    static started = false
    static jacked = {}

    static start()
    {
        Observer.started = true;

        Observer.hijack( MutationObserver,  function constructor()
        {
            alert("CAREFUL!! - MutationObserver is running here!");

            return (Observer.jacked.MutationObserver).constructor.apply(this, [...arguments]);
        });

        // if (!Observer.fixes[document.domain])
        // {
        //     dump("not listining on: "+document.domain);
        //     return;
        // };
        //
        // Observer.fixes[document.domain]()
    }

    static hijack(target, impose)
    {
        let waiting = setInterval(()=>
        {
            if ((typeof target.prototype) !== "object"){ return };
            if ((typeof target.prototype.constructor) !== "function"){ return };

            clearInterval(waiting);
            let name = target.prototype.constructor.name;
            dump("hijacking: "+name);
            Observer.jacked[name] = target;
            Object.defineProperty(target.prototype, "constructor", {writable:false, configurable:false, enumerable:false, value:impose});
        },0);
    }
}

let waiting = setInterval(() =>
{
    let exists = ((typeof MutationObserver) !== "undefined");

    if ( !exists )
    {
        console.log("observer waiting for `MutationObserver`");
        return
    };

    if ( Observer.started )
    {
        clearInterval(waiting);
        console.log("observer already started .. exiting");
        return
    };

    clearInterval(waiting);
    Observer.start();
}, 0);

优化实现方案

你的核心思路没问题,但原代码的劫持方式不够可靠,轮询机制也没必要。针对浏览器扩展场景,要确保代码优先执行,重点是利用扩展的document_start加载时机,直接重写全局MutationObserver即可:

// 保存原始构造函数
const OriginalMO = window.MutationObserver;

// 重写MutationObserver
window.MutationObserver = function(callback) {
    // 触发创建通知
    console.log("[监控] MutationObserver 被实例化");

    // 包装原始回调,捕获所有DOM变更
    const wrappedCallback = (mutations, observer) => {
        console.log("[监控] 捕获到DOM变更:", mutations);
        // 调用原始回调,保证原有逻辑正常运行
        callback(mutations, observer);
    };

    // 创建原始实例并返回
    return new OriginalMO(wrappedCallback);
};

// 同步原型方法,避免兼容性问题
Object.assign(window.MutationObserver.prototype, OriginalMO.prototype);
// 修正构造函数指向
window.MutationObserver.prototype.constructor = window.MutationObserver;

关键注意事项

  1. 确保优先执行:在扩展的manifest.json中,将content script的run_at设置为"document_start",这样代码会在页面所有脚本执行前完成重写:
{
  "manifest_version": 3,
  "name": "DOM变更监控插件",
  "version": "1.0",
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"],
      "run_at": "document_start"
    }
  ]
}
  1. 完整兼容:通过Object.assign同步原始原型的所有方法,避免页面脚本调用observe、disconnect等方法时出错。
  2. 轻量高效:无需轮询等待MutationObserver,document_start阶段window对象已初始化,可直接访问原始构造函数。
  3. 灵活扩展:在wrappedCallback中可以自定义处理逻辑,比如过滤特定类型的变更、记录日志或上报数据等。

内容的提问来源于stack exchange,提问作者Lusi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 16:55:22