如何从扩展程序中检测Google Chrome中的页面标题更改?

时间:2013-07-27 05:28:03

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

我正在创建Google Chrome扩展程序,我需要检测网页标题何时发生变化。页面的标题在Twitter中更改:(num) Twitter(参见下面的屏幕截图) - 当发布新推文时,数字会递增。例如:

enter image description here

我正在尝试检测在我的某个标签中加载的网址的标题更改,并在出现差异时播放哔声。此检查将在重复的时间间隔内完成,我认为可以使用setTimeOut()函数完成。

我创建了一个manifest.json,如下所示:

{
  "manifest_version": 2,

  "name": "Detect Page Title Changes",
  "description": "Blah",
  "version": "1.0",

  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "background.html"
  },
  "permissions": [
    "tabs"
  ]
}

然而,我对其余的一无所知。我搜索了文档1 2 并尝试了类似Stack Overflow线程的解决方案,例如this one我但是找不到任何适合我的要求。

你有什么建议吗?如果可能,请提供一个示例。

4 个答案:

答案 0 :(得分:17)

不要在评论中争论某种方法更好,让我更具建设性,并通过展示particular implementation我自己共同撰写,并解释一些问题来添加答案可能会遇到。 代码段指的是与Twitter不同的服务,但目标是相同的。实际上,此代码的目标是报告未读邮件的确切数量,因此您的邮件可能更简单。

我的方法基于an answer这里的SO,而不是轮询驱动(以固定间隔检查条件)事件驱动(被告知可能的情况变化)。

优点包括立即检测到更改(否则在下次轮询之前不会被检测到)并且在条件不变的情况下不会在轮询上浪费资源。不可否认,第二个论点在这里几乎不适用,但第一个论点仍然存在。


架构一览:

  1. 将内容脚本注入相关页面。

  2. 分析标题的初始状态,通过sendMessage向背景页面报告。

  3. 为标题更改事件注册处理程序。

  4. 每当事件触发并调用处理程序时,请分析标题的新状态,通过sendMessage向背景页面报告。


  5. 第1步已经有了问题。正常内容脚本注入机制,当在清单中定义内容脚本时,会在导航到与URL匹配的页面时将其注入页面。

    "content_scripts": [
      {
        "matches": [
          "*://theoldreader.com/*"
        ],
        "js": ["observer.js"],
        "run_at": "document_idle"
      }
    ]
    

    这非常有效,直到您的扩展程序重新加载。这可能在开发过程中发生,因为您正在应用您所做的更改,或者在已部署的实例中进行自动更新。然后会发生的是内容脚本在现有的打开页面中重新注入(直到导航发生,如重新加载)。因此,如果您依赖基于清单的注入,则还应考虑在扩展初始化时将编程注入包含在已打开的选项卡中:

    function startupInject() {
      chrome.tabs.query(
        {url: "*://theoldreader.com/*"},
        function (tabs) {
          for (var i in tabs) {
            chrome.tabs.executeScript(tabs[i].id, {file: "observer.js"});
          }
        }
      );
    }
    

    另一方面,在扩展重新加载时处于活动状态的内容脚本实例不会终止,但会被孤立:任何sendMessage或类似请求都将失败。因此,建议在尝试与父扩展进行通信时始终检查异常,并在失败时自行终止(通过删除处理程序):

    try {
      chrome.runtime.sendMessage({'count' : count});
    } catch(e) { // Happens when parent extension is no longer available or was reloaded
      console.warn("Could not communicate with parent extension, deregistering observer");
      observer.disconnect();
    }
    

    步骤2也有问题,但这取决于您正在观看的服务的具体情况。内容脚本范围内的某些页面不会显示未读项目的数量,但这并不意味着没有新消息。

    在观察了网络服务的工作原理后,我得出结论,如果标题改为没有导航的东西,如果正确的话,可以安全地假设新值,但对于初始标题,“无新项目”应该被忽略为不可靠。 / p>

    因此,分析代码会考虑它是初始读数还是处理更新:

    function notify(title, changed) {
      // ...
      var match = /^\((\d+)\)/.exec(title);
      var match_zero = /^The Old Reader$/.exec(title);
    
      if (match && match[1]) {
        count = match[1];
      } else if (match_zero && changed) {
        count = 0;
      }
      // else, consider that we don't know the count
      //...
    }
    

    在步骤2中使用初始标题和changed = false调用它。


    第3步& 4是“如何监视标题更改”的主要答案(以事件驱动的方式)。

    var target = document.querySelector('head > title');
    
    var observer = new window.MutationObserver(
      function(mutations) {
        mutations.forEach(
          function(mutation){
            notify(mutation.target.textContent, true);
          }
        );
      }
    );
    
    observer.observe(target, { subtree: true, characterData: true, childList: true });
    

    有关为何设置observer.observe的某些选项的具体信息,请参阅original answer

    请注意,使用notify = changed调用true,因此从“(1)旧阅读器”到“没有导航的旧阅读器”被认为是“ true“更改为零未读消息。

答案 1 :(得分:7)

  1. 创建event page

  2. 创建一个content script,在网页加载时会将其注入网页。

  3. 在内容脚本中,使用setInterval轮询页面以查看window.document.title是否发生了变化。

  4. 如果标题已更改,请使用chrome.runtime.sendMessage向您的活动页面发送消息。

  5. 在您的活动页面上,使用chrome.runtime.onMessageplay a sound收听讯息。

答案 2 :(得分:7)

在研究了Chrome的标签API之后,看起来没什么特别突出的帮助。但是,您应该能够将事件监听器附加到您感兴趣的选项卡的标题节点.DOMSubtreeModified变异事件在Chrome中有效,并且在普通的html文档中进行快速测试证明对我有用 - 应该与扩展内容没有区别。

var title = document.getElementsByTagName('title')[0];

if (title) {
    title.addEventListener('DOMSubtreeModified', function (e) {
        // title changed
    }, false);
}

答案 3 :(得分:7)

chrome.tabs.onUpdated.addListener放在后台脚本中:

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
   console.log(changeInfo);
});

changeInfo是一个包含标题更改的对象,例如这里:

Screenshot of changeInfo object in console

然后可以对对象进行过滤,以便仅在changeInfo包含标题更改时才会执行操作。对于其他操作,例如通过页面内容/操作响应页面标题更改,您可以在满足任何条件后从侦听器内部向内容脚本发送消息。