我在理解WebExtensions notification.onClicked
事件的文档时遇到了问题。
最终,当您点击它时,我试图将通知的文本复制到剪贴板。但是,现在我在理解回调事件时遇到问题,或者我必须插入notification.onClicked
函数。
目前,我不知道为什么{
"description": "Test Webextension",
"manifest_version": 2,
"name": "Σ",
"version": "1.0",
"permissions": [
"<all_urls>",
"notifications",
"webRequest"
],
"background": {
"scripts": ["background.js"]
}
}
听众什么都不做。
我的代码(将所有代码展示为WebExtension Firefox插件所需的代码):
的manifest.json
'use strict';
function logURL(requestDetails) {
notify("Testmessage");
chrome.notifications.onClicked.addListener(function() {
console.log("TEST TEST");
});
}
function notify(notifyMessage) {
var options = {
type: "basic",
iconUrl: chrome.extension.getURL("icons/photo.png"),
title: "",
message: notifyMessage
};
chrome.notifications.create("ID123", options);
}
chrome.webRequest.onBeforeRequest.addListener(
logURL, {
urls: ["<all_urls>"]
}
);
background.js
{{1}}
答案 0 :(得分:2)
首先,您需要在Firefox 47.0+中对此进行测试,因为在版本47.0中添加了对chrome.notifications.onClicked()
的支持。虽然这可能不是你的问题,但这是一个有用的可能性。
您的代码存在多个问题。有些在您的代码中,但主要是您遇到了Firefox错误。
Firefox Bug:
您的主要问题是,如果您尝试过快地创建通知,则会遇到Firefox混乱的Firefox。因此,我已经实现了通知队列,并且速率限制了通知的创建。什么是#34;太快&#34;可能与操作系统和CPU有关,因此您最好在注意方面出错,并将调用chrome.notifications.create()
之间的延迟设置为更高的值。在下面的代码中,延迟是500毫秒。我在MDN的chrome.notifications.create()
页面和Chrome incompatibilities页面上添加了有关此问题的说明。
添加同一个侦听器的多个副本:
您在代码中出错的主要原因是您使用chrome.notifications.onClicked.addListener()
多次将匿名函数作为侦听器添加到同一事件中。这是事件处理程序的一般问题。当您使用匿名函数时,每次尝试添加它时,它都是一个不同的实际函数,因此多次添加相同的功能(在多个相同的函数中)。你不应该添加函数,它们对同一个事件多次执行完全相同的操作。这样做几乎总是程序中的错误,并导致意外操作。
在这种情况下,每次用户点击通知时,多个函数最终都会向控制台输出多行TEST TEST
。对于每个Web请求,每次点击输出的行数将增加一,从而导致调用logURL
。
防止这样做的方法是确保只将侦听器添加一次。如果您使用的是匿名函数,则只能通过确保只执行addListener
(或addEventlistener
)一次(通常只添加您的监听器)来执行此操作主代码(不是来自函数内),或来自仅被称为一次的函数。或者,您可以直接在全局范围内(或所有位置可访问的其他范围)命名/定义侦听器函数您尝试添加侦听器的位置)(例如function myListener(){...}
)。然后,当您添加myListener
时,您总是指的是JavaScript自动阻止您以相同方式添加到同一事件不止一次。
应该注意的是,如果你试图从另一个监听器添加一个匿名函数作为监听器,你几乎总是做错了。将相同的匿名侦听器的副本多次添加到同一事件是一个常见的错误。
访问通知文字:
虽然您没有实现有关使用通知文本的任何内容,但您声明要在用户单击通知时将通知文本添加到剪贴板。您无法从chrome.notifications
API的任何部分获取通知文本。因此,您必须自己存储该信息。下面的代码实现了一个Object,这样就可以在chrome.notifications.onClicked()
处理程序中访问文本。
示例代码:
下面的代码实现了我相信你的愿望。它只是在访问chrome.notifications.onClicked()
侦听器中的通知文本时创建并单击通知。它没有实现关于将文本放入剪贴板的部分,因为实际上并没有在您的问题的代码中实现。我在代码中添加了自由派评论来解释发生了什么,并提供了相当多的console.log()
输出来帮助显示正在发生的事情。我已经在Firefox Developer Edition(目前为v51.0a2)和Google Chrome中进行了测试。
background.js (对 manifest.json 没有任何更改):
'use strict';
//* For testing, open the Browser Console
var isFirefox = window.InstallTrigger?true:false;
try{
if(isFirefox){ //Only do this in Firefox
//Alert is not supported in Firefox. This forces the Browser Console open.
//This abuse of a misfeature works in FF49.0b+, not in FF48
alert('Open the Browser Console.');
}
}catch(e){
//alert throws an error in Firefox versions below 49
console.log('Alert threw an error. Probably Firefox version below 49.');
}
//*
//Firefox gets confused if we try to create notifications too fast (this is a bug in
// Firefox). So, for Firefox, we rate limit showing the notifications.
// The maximum rate possible (minimum delay) is probably OS and CPU speed dependent.
// Thus, you should error on the side of caution and make the delay longer.
// No delay is needed in Chrome.
var notificationRateLimit = isFirefox ? 500:0;//Firefox:Only one notification every 500m
var notificationRateLimitTimeout=-1; //Timeout for notification rate limit
var sentNotifications={};
var notificationsQueue=[];
var notificationIconUrl = chrome.extension.getURL("icons/photo.png");
function logURL(requestDetails) {
//console.log('webRequest.onBeforeRequest URL:' + requestDetails.url);
//NOTE: In Chrome, a webRequest is issued to obtain the icon for the notification.
// If Chrome finds the icon, that webRequest for the icon is only issued twice.
// However, if the icon does not exist, then this sets up an infinite loop which
// will peg one CPU at maximum utilization.
// Thus, you should not notify for the icon URL.
// You should consider excluding from notification all URLs from within your
// own extension.
if(requestDetails.url !== notificationIconUrl ){
notify('webRequest URL: ' + requestDetails.url);
}
//Your Original code in the Question:
//Unconditionally adding an anonymous notifications.onClicked listener
// here would result in multiple lines of 'TEST TEST' ouput for each click
// on a notification. You should add the listener only once.
}
function notify(notifyMessage) {
//Add the message to the notifications queue.
notificationsQueue.push(notifyMessage);
console.log('Notification added to queue. message:' + notifyMessage);
if(notificationsQueue.length == 1){
//If this is the only notification in the queue, send it.
showNotificationQueueWithRateLimit();
}
//If the notificationsQueue has additional entries, they will get
// shown when the current notification has completed being shown.
}
function showNotificationQueueWithRateLimit(){
if(notificationRateLimitTimeout===-1){
//There is no current delay active, so immediately send the notification.
showNextNotification();
}
//If there is a delay active, we don't need to do anything as the notification
// will be sent when it gets processed out of the queue.
}
function showNextNotification() {
notificationRateLimitTimeout=-1; //Indicate that there is no current timeout running.
if(notificationsQueue.length === 0){
return; //Nothing in queue
}
//Indicate that there will be a timeout running.
// Neeed because we set the timeout in the notifications.create callback function.
notificationRateLimitTimeout=-2;
//Get the next notification from the queue
let notifyMessage = notificationsQueue.shift();
console.log('Showing notification message:' + notifyMessage);
//Set our standard options
let options = {
type: "basic",
//If the icon does not exist an error is generated in Chrome, but not Firefox.
// In Chrome a webRequest is generated to fetch the icon. Thus, we need to know
// the iconUrl in the webRequest handler, and not notify for that URL.
iconUrl: notificationIconUrl,
title: "",
message: notifyMessage
};
//If you want multiple notifications shown at the same time, your message ID must be
// unique (at least within your extension).
//Creating a notification with the same ID causes the prior notification to be
// destroyed and the new one created in its place (not just the text being replaced).
//Use the following two lines if you want only one notification at a time. If you are
// actually going to notify on each webRequest (rather than doing so just being a way
// to test), you should probably only have one notification as they will rapedly be
// off the screen for many pages.
//let myId = 'ID123';
//chrome.notifications.create(myId,options,function(id){
//If you want multiple notifications without having to create a unique ID for each one,
// then let the ID be created for you by using the following line:
chrome.notifications.create(options,function(id){
//In this callback the notification has not necessarily actually been shown yet,
// just that the notification ID has been created and the notification is in the
// process of being shown.
console.log('Notification created, id=' + id + ':: message:' + notifyMessage);
logIfError();
//Remember the text so we can get it later
sentNotifications[id] = {
message: notifyMessage
}
//Show the next notification in the FIFO queue after a rate limiting delay
// This is called unconditionally in order to start the delay should another
// notification be queued, even if one is not in the queue now.
notificationRateLimitTimeout = setTimeout(showNextNotification
,notificationRateLimit);
});
}
function logIfError(){
if(chrome.runtime.lastError){
let message =chrome.runtime.lastError.message;
console.log('Error: ' + message);
}
}
chrome.webRequest.onBeforeRequest.addListener(
logURL, {
urls: ["<all_urls>"]
}
);
//Add the notifications.onClicked anonymous listener only once:
// Personally, I consider it better practice to use a named function that
// is defined in the global scope. Doing so prevents inadvertantly adding
// it multiple times. Although, your code should be written such that you
// don't do that anyway.
chrome.notifications.onClicked.addListener(function(id) {
//We can not get the notification text from here, just the ID. Thus, we
// have to use the text which was remembered.
console.log('Clicked notification message text: ', sentNotifications[id].message);
//In Firefox the notification is automatically cleared when it is clicked.
// If you want the same functionality in Chrome, you will need to clear() it
// yourself:
//Always do this instead of only when not in Firefox so that it remains consistent
// Even if Firefox changes to match Chrome.
chrome.notifications.clear(id);
//This is the last place we use the text of the notification, so we delete it
// from sentNotifications so we don't have a memory leak.
delete sentNotifications[id];
});
//Test the notifications directly without the need to have webRequests:
notify('Background.js loaded');
notify('Second notification');
在处理此问题的过程中,我发现Chrome和Firefox之间存在多种不兼容性。我正在更新MDN以提及MDN文档中的不兼容性。