Chrome扩展程序:如何在Ajax请求时重新加载/重新执行内容脚本

9
我想为特定网站执行内容脚本(注入按钮或更改链接),但我希望在用户浏览网站时执行。问题是,随着用户的浏览,网页会通过ajax请求动态构建。之前我曾通过将JavaScript注入到网页中来解决这个问题。现在我想知道是否有更好的方法可以在我的内容脚本中注册ajaxComplete事件或类似事件,以便可以重新执行。我可以执行以下操作:
function listener()
{
    console.debug("listener fired.");
}
document.addEventListener("DOMSubtreeModified", listener, false);

然而,在页面加载期间,这会触发太多次。


如果网站使用散列 (#...) 或者新的 HTML5 历史记录 API,则需要查找特定事件(onhashchange, onpopstate). - pimvdb
他们不是。请参考网站beatport - Setheron
在Chrome上,我可以看到URL正在更改,而页面并没有导航离开。我怀疑他们确实使用了历史API。他们在源代码中使用了history.pushState - pimvdb
我怎么寻找这些事件?我不太会JS - Setheron
@pimvdb:他们只是在第一次加载时简单地推送状态。每次导致URL更改的单击都不会触发其他推送。 - Setheron
2个回答

8

据我所知,没有任何AJAX监听器可以使用,但即便有也帮助不大,因为您需要捕获页面修改的时刻,而不是发送/接收AJAX请求的时刻(页面修改通常会在稍后发生,并且可能根本与AJAX请求无关)。

DOMSubtreeModified是正确的方法,只需实现一些保护措施来防止过于频繁的调用即可:

function listener()
{
    console.debug("listener fired.");
}

var timeout = null;
document.addEventListener("DOMSubtreeModified", function() {
    if(timeout) {
        clearTimeout(timeout);
    }
    timeout = setTimeout(listener, 500);
}, false);

这样,如果在500毫秒内没有其他事件发生,它将触发listener

我尝试了上面的代码。它可以工作!但是每次我对页面进行更改时,监听器都会被触发,因此它变成了一种无限循环。有什么建议吗? - Nikhil Bhandari
我也遇到了这个问题,它从未停止。 - qichunren

5
我找到的最佳答案有点有趣,涉及到内容脚本和background.html文件之间的消息传递
我将发布代码,然后解释:

Background.html

  function updatePageAction(tabId)
  {
    chrome.tabs.sendRequest(tabId, {is_content_script: true}, function(response) {
      if (response.is_content_script)
        chrome.pageAction.show(tabId);
    });
  };

  chrome.tabs.onUpdated.addListener(function(tabId, change, tab) {
    if (change.status == "complete") {
      updatePageAction(tabId);
    }
  });

content_script.js

// The background page is asking us to find an address on the page.
if (window == top) {
  chrome.extension.onRequest.addListener(function(req, sender, sendResponse) {
        if (req.is_content_script)
            start_content_script();
            sendResponse({is_content_script: true});
  });
};

您想解决在DOM更改时更新或重新执行脚本的问题。幸运的是,DOM更改涉及URL更改(尽管这是用于更新页面的AJAX DOM更改)。
但是,URL更改会触发onUpdated事件。但是,每个选项卡都会触发这些“事件”,我们希望确保只关心与我们的内容脚本匹配的那个选项卡(可以在清单中指定匹配!)。
通过向当前选项卡中执行的content_script传递消息,我们询问“您是我的内容脚本吗?如果是,请重新启动。”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接