我正在创建一个Google Chrome扩展程序,我需要检测页面标题何时更改。该页面的标题像在Twitter中一样被更改:((num) Twitter
请参见下面的屏幕截图)-发布新的tweet时,数字将递增。例子:
我试图检测在我的一个标签中加载的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
你有什么建议吗?如果可能,请提供示例。
与其在评论中争论某种方法更好,不如让我更具建设性,并通过展示我共同编写的特定实现并解释一些可能遇到的难题来添加答案。代码段指的是与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)旧阅读器”到没有导航的“旧阅读器”被认为是“真实”的更改,即未读邮件为零。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句