[英]How to detect page title change in Google Chrome from an extension?
我正在创建一个 Google Chrome 扩展程序,我需要检测页面标题何时发生变化。 页面标题的更改与 Twitter 类似: (num) Twitter
(见下面的屏幕截图)- 当发布新推文时,数字会增加。 例子:
我正在尝试检测加载到我的一个选项卡中的 URL 的标题更改,并在出现差异时播放哔声。 此检查将在重复的时间间隔内完成,我认为可以使用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 线程上尝试了解决方案,例如这个我,但找不到任何适合我的要求的东西。
你有什么建议吗? 如果可能,请提供一个示例。
与其在评论中争论某种方法更好,不如让我更有建设性,并通过展示我自己共同编写的特定实现来添加答案,并解释您可能遇到的一些问题。 代码片段指的是与 Twitter 不同的服务,但目标是相同的。 实际上,此代码的目标是报告未读消息的确切数量,因此您的目标可能更简单。
我的方法基于 SO 上的答案,而不是轮询驱动(以固定时间间隔检查条件)是事件驱动(通知条件的潜在变化)。
优点包括立即检测变化(否则直到下一次轮询才会检测到),并且不会在条件不变的情况下在轮询上浪费资源。 诚然,第二个论点在这里几乎不适用,但第一个论点仍然成立。
架构概览:
将内容脚本注入相关页面。
分析标题的初始状态,通过sendMessage
报告给后台页面。
为标题更改事件注册处理程序。
每当事件触发并调用处理程序时,分析标题的新状态,通过sendMessage
报告给后台页面。
步骤 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 步也有一个问题,尽管这取决于您正在观看的服务的具体情况。 内容脚本范围内的某些页面不会显示未读项目的数量,但这并不意味着没有新消息。
在观察 Web 服务的工作方式后,我得出结论,如果标题更改为没有导航的内容,如果正确,假设新值是安全的,但对于初始标题“没有新项目”应该被忽略为不可靠。
因此,分析代码考虑了它是初始读取还是处理更新:
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
选项的详细信息,请参阅原始答案。
请注意, notify
是使用changed
= true
调用的,因此从“(1) The Old Reader”到“The Old Reader”没有导航被认为是对零未读消息的“真实”更改。
创建一个活动页面。
创建一个在网页加载时注入网页的内容脚本。
在内容脚本中,使用setInterval
轮询页面以查看window.document.title
更改。
如果标题已更改,请使用chrome.runtime.sendMessage
向您的活动页面发送消息。
在您的活动页面上,使用chrome.runtime.onMessage
收听消息并播放声音。
在研究了 Chrome 的 tabs API 之后,看起来没有什么可以直接帮助你。 但是,您应该能够将事件侦听器附加到您感兴趣的选项卡的标题节点。 DOMSubtreeModified 突变事件在 Chrome 中有效,并且在普通 html 文档中的快速测试证明对我有用 -应该与扩展内没有什么不同。
var title = document.getElementsByTagName('title')[0];
if (title) {
title.addEventListener('DOMSubtreeModified', function (e) {
// title changed
}, false);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.