我正在创建一个 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 线程上尝试了解决方案,例如 this one但我找不到任何适合我要求的东西。
你有什么建议吗?如果可能,请提供一个示例。
最佳答案
与其在评论中争论某种方法更好,不如让我更有建设性并通过显示 particular implementation 来添加答案。我自己共同撰写,并解释了您可能遇到的一些问题。 代码片段指的是与 Twitter 不同的服务,但目标是相同的。事实上,此代码的目标是报告未读消息的确切数量,因此您的代码片段可能会更简单。
我的方法基于 an answer这里关于SO,而不是轮询驱动(以固定时间间隔检查条件)是事件驱动(通知条件的潜在变化)。
优点包括立即检测到更改(否则直到下一次轮询才会检测到),并且在条件未更改时不会在轮询上浪费资源。诚然,第二个论点在这里几乎不适用,但第一个论点仍然成立。
<小时/>架构概览:
将内容脚本插入相关页面。
分析标题的初始状态,通过
sendMessage
报告给后台页面。注册标题更改事件的处理程序。
每当事件触发并调用处理程序时,分析标题的新状态,通过
sendMessage
向后台页面报告。
第 1 步已经有一个问题了。正常的内容脚本注入(inject)机制,当在 list 中定义内容脚本时,会在导航到与 URL 匹配的页面时将其注入(inject)到页面中。
"content_scripts": [
{
"matches": [
"*://theoldreader.com/*"
],
"js": ["observer.js"],
"run_at": "document_idle"
}
]
这工作得很好,直到您的扩展程序重新加载。当您应用所做的更改时,这可能会在开发中发生,或者在自动更新的部署实例中发生。然后会发生的情况是,内容脚本不会重新注入(inject)现有的打开页面中(直到发生导航,例如重新加载)。因此,如果您依赖基于 list 的注入(inject),您还应该考虑在扩展初始化时将编程注入(inject)到已打开的选项卡中:
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 步也有一个问题,不过这取决于您正在观看的服务的具体情况。内容脚本范围内的某些页面不会显示未读邮件的数量,但这并不意味着没有新邮件。
在观察网络服务的工作原理后,我得出的结论是,如果标题在没有导航的情况下更改为某些内容,则可以安全地假设新值(如果正确),但对于初始标题“无新项目”应因不可靠而被忽略。
因此,分析代码会考虑是初始读取还是处理更新:
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) The Old Reader”变为“The Old Reader” "没有导航被认为是零未读消息的“真正”更改。
关于javascript - 如何从扩展程序检测 Google Chrome 中的页面标题更改?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39879733/