document.open删除所有窗口侦听器

时间:2016-05-12 03:01:13

标签: javascript dom google-chrome-extension javascript-events

我正在撰写Chrome扩展程序。它用于记录用户浏览网页时的行为。它通过使用Chrome content script向客户的网页添加事件监听器来实现。

content script中的代码如下:

var recordingEvents = ['click', 'input', 'change'];
recordingEvents.forEach(function (e) {
    window.addEventListener(e, handler, true);
});

自定义页面示例:

<script>
function reload() {
    var ifrw = document.getElementById("iframeResult").contentWindow;
    ifrw.document.open();
    ifrw.document.write("<div>abc</div>");  
    ifrw.document.close();
}
</script>
<body>
<input type="submit" onclick="reload();" value="Reload" />
<iframe id="iframeResult"></iframe>
</body>

它使用document.opendocument.write来重写iframe的内容。

这是一个问题。我的事件侦听器附加到window对象。并document.open删除其所有事件侦听器。如下图所示。

enter image description here

有没有办法避免document.open删除事件侦听器?或者观察document.open,我可以手动重新添加听众吗?

2 个答案:

答案 0 :(得分:0)

我发现这个问题试图解决完全相同的问题。

这是一个规范https://html.spec.whatwg.org/multipage/webappapis.html#dom-document-open,表示在document.open当前文档被销毁并替换为新文档。我希望某些事件可以像#34; loading&#34;仍然保留,没有运气。 这是我的检测代码:

const testEventName = 'TestEvent';
let tm;

function onTestEvent() {
    clearTimeout(tm);
}

function listenToTestEvent() {
    document.addEventListener(testEventName, onTestEvent);
}

listenToTestEvent();

function onLostEvents() {
    console.log('events are lost');
    listenToTestEvent();
    // DO THING HERE
}


function checkIfEventsAreLost() {
    document.dispatchEvent(new CustomEvent(testEventName));
    tm = setTimeout(onLostEvents);
}

new MutationObserver(checkIfEventsAreLost).observe(document, { childList: true });

重新创建文档时,childList已更改(新的documentElement节点),这是我考虑过检测文档替换的最佳触发器。

请注意,甚至听众也会在setTimeout(..., 0)

之前开火

答案 1 :(得分:0)

这是对 @Viller's answer 为何有效的详细说明。我正在将此作为一个新答案,因为它不适合评论

TestEvent 事件是一个特殊的事件,用于监控文档中先前设置的事件何时被删除。

特别是,这说明了 document.open 的情况,它不仅从文档中删除了所有侦听器,还从窗口中删除了所有侦听器。

总体思路是为一个名为 TestEvent 的自定义事件设置一个监听器,它清除超时。仅当文档发生变异并由变异观察者触发时才会设置此类超时。

由于超时将操作安排在至少在事件循环的下一个滴答期间发生,因此可以在此之前清除此类超时,从而避免同时执行其回调。而且,由于 TestEvent 事件处理程序清除了该超时,所以清除超时的事实意味着侦听器仍处于连接状态。另一方面,如果在下一次滴答之前没有清除超时,则表示事件已被删除并且需要新的“设置”。