在 Firefox 中加载附加组件

在本教程中,我们将介绍如何创建附加组件,允许用户在指定时间使用自定义文本创建警报 。我们将介绍如何创建基本加载项、添加弹出窗口和选项页面、添加权限、存储信息、发送通知以及创建用于发送通知的后台脚本 。
本教程不需要任何创建附加组件或任何浏览器扩展的经验 。您只需要了解一些基础知识 。您可以在此存储库中找到本教程的代码,也可以在此处找到已创建的附加组件 。
设置我们的插件
创建附加组件的第一步是创建.json文件 。此文件是附加组件所需的唯一文件 。.json文件的基本格式应包括以下键:
这些是任何附加组件的必填字段 。以下两个是可选的,但建议使用:
对于我们的附加组件api版本菜单使用中,让我们首先创建一个名为–addon. 然后添加一个.json内容如下:
{"name": "personalized-alarms","version": "0.0.1","description": "Create personalized alarms","manifest_version": 2,"icons": {"16": "assets/images/icon16.png","32": "assets/images/icon32.png","48": "assets/images/icon48.png","128": "assets/images/icon128.png"}}
如您所见,icons键是一个对象,其中包含文件大小和路径的键 。该路径是相对于附加组件的根目录,即其所在的位置.json 。在本教程中,我使用的下载图标通过的表情符号,我可以下载需要以及不同尺寸 。
如果您正在跟进,请从我们的存储库中获取这些文件并将它们放在适当的目录 ( //) 中 。
这就是创建附加组件所需的全部内容!
在中加载附加组件
要测试我们的附加组件并在稍后将其上传到的开发人员中心之前能够对其进行调试,请打开  , 然后从右侧菜单中选择附加组件和主题,或使用快捷方式ctrl+ shift+ A 。然后 , 单击 Your 旁边的“”图标并选择Debug Add-ons 。
将为 打开一个新页面 。
单击LoadAdd-on按钮并选择.json您刚刚创建的文件 。如果一切正常 , 您将看到新创建的附加组件,其中包含有关它的一些信息以及我们在.json.
添加弹出窗口
可以通过不同的方法访问附加组件,其中之一是添加弹出页面 。添加弹出页面时,扩展程序的图标将显示在工具栏中,一旦用户单击它,您指定的弹出页面就会显示出来 。
我们将使用弹出页面向用户显示即将到来的警报列表和一个添加新警报的链接,该链接将用户带到选项页面(我们将在下一节中讨论) 。
popup.html在项目根目录中创建一个文件,内容如下:
Personalized AlarmsUpcoming Alarms

    Add an Alarm
    如您所见,它只是一个 HTML 文档 。我们也加入.min.css到/css和链接在这里它 , .min.js在/js/.min.js和链接它 。这两个库只是为了让事情变得更容易,但您不必实际使用它们 。你可以在这里和这里从我们的仓库中获取它们 。
    在页面内容中,我们将显示即将到来的警报列表以及指向选项页面的链接 。
    使弹出窗口工作的下一步是在 中添加以下内容.json:
    "browser_action": {"default_popup": "popup.html","browser_style": true}
    是一个具有多个选项的对象,但唯一必须的一个是 , 它是从附加组件根目录到弹出窗口的相对路径 。不是强制性的,但建议将其设置为true. 这意味着将注入浏览器的默认样式,以确保加载项的弹出样式与浏览器的其余部分相似 。
    这就是添加弹出窗口所需的全部内容 。转到我们之前访问的临时附加组件页面,然后单击附加组件的重新加载按钮 。这将使检查.json任何更改并应用它们 。
    完成后,您将能够在工具栏菜单中看到扩展程序的图标 。
    如果你点击它 , 你可以看到我们刚刚创建的弹出页面 。
    我们的弹出窗口中还剩下两件事情以使其功能齐全:使用存储来获取即将到来的警报 , 并使“添加警报”链接将用户带到选项页面 。
    使用存储
    浏览器扩展中的存储允许我们存储与扩展或用户相关的数据 , 无论是在机器本地,还是基于他们的帐户同步 。本地存储将信息本地存储在浏览器中,这意味着如果用户使用来自另一台机器的同一电子邮件登录 ,则存储的信息将不会出现在那里 。同步存储存储当前登录用户的信息,这使得该信息在用户登录的任何地方都可用 。
    同步存储应该用于用户希望在任何地方都可用的某些设置,而本地存储应该用于仅与当前浏览器安装相关的信息或选项 。
    在我们的示例中,我们将在用户登录的任何地方提供警报,因此我们将它们存储在同步存储中 。但是假设我们要添加一个“临时禁用”选项,将警报静音一段时间 。在这种情况下,使用本地存储可能更合适 。
    可以通过存储 API通过get和set方法轻松访问存储,但首先,我们需要请求在我们的附加组件中使用的权限 。这可以在里面完成.json:
    "permissions": ["storage"],
    当用户安装您的加载项时,他们将看到您需要哪些权限并需要他们接受才能安装您的加载项 。
    为了能够在本地测试附加组件,我们还需要添加另一件事:显式附加组件 ID以便能够使用。为此 , 也将其添加到.json:
    "browser_specific_settings": {"gecko": {"id": "addon@example.com","strict_min_version": "42.0"}}
    这只是为了能够在本地测试它 。发布后,我们将从清单中删除它 。
    接下来我们要做的是创建一个新/js/popup.js文件,该文件将从存储中获取警报并显示它们 。
    要从存储中获取项目,您可以使用..sync.get或..local.get 。这取决于您是将信息存储在同步存储还是本地存储中 。在我们的例子中 , 我们将警报存储在同步存储中,因此我们将使用..sync.get. 需要注意的是,..sync.*和下的所有方法..local.*都具有相同的签名并接受/返回相同的类型 。
    ..sync.get接受一个参数:一个字符串数组,这些字符串是我们正在检索的数据的键 。这些键是在我们设置存储时定义的(我们将在下一节中讨论) 。此函数返回一个承诺,该承诺解析为包含我们在第一个参数中指定的键及其值(如果存在)的对象 。
    注意:如果您要使加载项与兼容,请务必查看“使加载项与兼容”部分 。
    /js/popup.js使用以下内容创建:
    $(document).ready(() => {const listElement = $('#alarmsList');browser.storage.sync.get(['alarms']).then((result) => {if (result.alarms && result.alarms.length) {//loop over the alarms and display themresult.alarms.forEach((alarm) => {appendItem(alarm.content, alarm.time);});} else {//show no items availableappendItem('No alarms are available');}});function appendItem(content, badgeContent = null) {listElement.append(`
  • ${content}${badgeContent ? `${badgeContent}` : ''}
  • `);}});

    您还需要将此文件包含在popup.html:
    ...
    当文档准备好时,我们使用..sync.get来获取用户创建的警报 。然后我们检查是否有任何警报 。如果有,我们将遍历它们并使用 函数显示它们,该函数只是将一个 HTML 列表元素附加li到#. 如果没有可用的警报,我们只是显示“没有可用的项目” 。
    如果我们现在重新加载附加组件,您会注意到添加了一个新安装的附加组件 。这是因为我们在.json. 您可以删除旧的以避免冲突 。
    您会注意到我们的弹出窗口中没有任何变化 , 因为我们还没有添加任何警报 。我们将在下一节中执行此操作 。
    添加选项页面
    要允许您的用户自定义或编辑附加组件中的选项或设置,您可以创建一个 HTML 页面,其中包含这些选项以及设置或更改它们背后的逻辑 。然后在.json文件中链接到它 。
    在我们的附加组件中,我们将使用“选项”页面来允许用户创建警报 。让我们首先创建文件.html 。您可以在附加项目目录中的任何位置创建它 。我们将在项目的根目录中创建它,内容如下:
    OptionsAdd Alarm
    在这里 , 我们只显示一个包含两个输入字段的表单:“Alarm Name” , 这是发送通知时在警报中显示的文本,以及“Time” , 即设置闹钟的时间 。
    我们需要创建/js/.js,它将侦听同步存储中和 设置的事件,向数组添加一个新警报 。
    与我们使用该get方法类似 , 要设置存储,我们可以使用..sync.set或..local.set , 具体取决于我们是在本地存储数据还是在所有登录之间同步实例 。由于我们将警报存储在 中sync,因此我们将使用..sync.set 。
    该set方法采用一个参数,该参数是键和值的对象 。关键是我们稍后用来检索值的东西,就像我们之前对get.
    /js/.js使用以下内容创建:
    $(document).ready(() => {const nameElm = $('#name');const timeElm = $('#time');const formElm = $('form');formElm.on('submit', () => {$('.alert').remove(); //remove previous success alerts, if any//get existing alarmsbrowser.storage.sync.get(['alarms']).then((result) => {let alarms = result.alarms;const alarmName = nameElm.val().trim() + '_' + (Math.random() * 100);if (!alarms) {alarms = [];}alarms.push({content: nameElm.val().trim(),time: timeElm.val(),alarmName});//set alarms in the storagebrowser.storage.sync.set({alarms}).then(() => {//TODO schedule notificationformElm.prepend('Alarm added successfully');nameElm.val('');timeElm.val('');});});return false; //disable default form submit action});});
    在提交表单时 , 我们首先检索存储的警报(如果有) 。然后 , 我们将通过表单创建的新警报推送到数组 。注意我们是如何创建一个变量的 。我们将使用这个变量来创建一个独特的警报,然后在用户删除它时取消它 。最后,我们使用..sync.set来设置新数组 。
    您可能还注意到我们添加了一条TODO评论,我们将在下一部分中安排通知 。
    我们的选项页面现已准备就绪 。要使其可用,我们首先需要将以下内容添加到.json:
    "options_ui": {"page": "options.html","browser_style": false}
    这会告诉在哪里可以找到我们的选项页面 。我们还设置为,false因为我们不希望的样式覆盖样式 。
    其次 , 我们现在将使弹出窗口中的链接将用户带到选项页面 。为此,我们在附加到 的新事件侦听器中使用方法..()# 。我们将添加以下内容/js/popup.js:
    $(document).ready(() => {...// New code here$('#optionsLink').on('click', () => {browser.runtime.openOptionsPage();});function appendItem(content, badgeContent = null) { ... }});
    现在,当用户单击“添加警报”链接时,它会将他们带到“选项”页面 。
    转到临时附加组件页面,然后单击重新加载按钮 。现在,我们的选项页面将被注册 。
    让我们来测试一下 。打开弹出窗口,然后单击“添加警报” 。它应该会带您到附加组件页面中的“首选项”选项卡,内容将是我们在.html页面中添加的内容 。
    现在,尝试添加任何名称和时间的测试警报,然后单击“添加警报” 。之后您应该能够在弹出窗口中看到它 。
    我们还需要对 做一个改动/js/.js , 就是显示时间晚于当前时间的闹钟 。将调用更改..sync.get为以下内容:
    browser.storage.sync.get(['alarms']).then((result) => {if (result.hasOwnProperty('alarms') && result.alarms) {//get current timeconst minutes = (new Date).getMinutes().toString().padStart(2, '0');const hours = (new Date).getHours().toString().padStart(2, '0');const now = new Date('1970-01-01T' + hours + ':' + minutes + 'Z').getTime();//loop over the alarms and display themresult.alarms.forEach((alarm) => {const alarmTime = new Date('1970-01-01T' + alarm.time + 'Z').getTime();if (alarmTime > now) {appendItem(alarm.content, alarm.time);}});} else {//show no items availableappendItem('No alarms are available');}});
    这会检查每个警报的时间是否大于当前时间,然后显示它 。我们将时间格式化的原因'1970-01-01T' + alarm.time + 'Z'是因为我们正在创建独立于日期的警报 。这只是为了使教程更简单 。在计算当前时间时,当它们是一位数时,我们还会填充hours并使用零,因为所需的格式对于new Date两个数字都应该有两位数 。
    如果您现在查看 , 您会注意到我们添加的上一个闹钟是否显示取决于其时间 。您还可以在其他时间测试添加新闹钟以查看它是否出现在弹出窗口中 。
    调度通知
    要发送通知,我们需要使用 API和 API 。警报 API 允许我们安排在特定时间触发的“警报” 。然后我们可以为事件添加一个事件侦听器,并在那时使用API 发送通知 。
    要使用API 和API,我们需要为每个 in 添加必要的权限.json,就像我们之前对API 所做的一样:
    "permissions": ["storage","alarms","notifications"],
    接下来我们要做的是用TODO在/js/.js.
    要创建警报,我们使用..函数,向其传递两个参数 。第一个是警报的名称 。这允许我们在附加组件中拥有不同类型的警报,并根据名称采取不同的行动 。第二个是选项对象:
    所有这些选项都是可选的 。如果你没有通过它们中的任何一个 , 警报将在创建后立即触发一次 。如果您需要在指定的时间触发一次警报,只需传递when要触发的时间即可 。如果您想在指定的分钟数后触发一次警报,则只需通过. 如果您想在指定的分钟数内重复触发警报 , 则只需通过. 除非通过,否则警报只会触发一次 。
    在我们的插件中,我们需要闹钟每天在用户创建闹钟时输入的指定时间触发一次 。因此,我们将使用的组合when和 。
    将TODO注释替换/js/.js为以下内容:
    //create a new alarmconst currentDate = new Date();const currentMonth = (currentDate.getMonth() + 1).toString().padStart(2, '0');const currentDay = currentDate.getDate().toString().padStart(2, '0');//same as before, add 0 to month and day if they're less than 10browser.alarms.create(alarmName, {when: new Date(currentDate.getFullYear() + '-' + currentMonth + '-' + currentDay + 'T' + timeElm.val()).getTime(),periodInMinutes: 1440,});
    作为第一个参数 , 我们传递我们之前创建的唯一警报名称 。附加组件中的警报名称应该是唯一的,因为如果不是,新添加的警报名称将覆盖具有相同名称的前一个警报名称 。在对象中,我们传递用户在when属性中选择的时间,因为我们传递的是1440,因为这是一天中的分钟数 。
    和以前一样 , 0如果月份和日期小于一位数,我们也会填充它们以确保它们是两位数 , 因为这是new Date.
    这意味着警报将在用户每天输入的指定时间触发一次 。
    现在我们已经成功创建了警报,接下来我们需要做的是监听这些警报何时触发,当它们触发时,向用户发送通知 。为此,我们需要使用后台脚本 。
    后台脚本
    加载项、弹出窗口、选项页面或任何其他页面仅在我们打开它们时才处于活动状态 。这意味着如果我们在弹出窗口或任何其他页面内监听事件,监听器只会在我们打开它们后工作 。在一天中的不同时间收听闹钟时api版本菜单使用中,这不会有帮助 。
    为此,我们需要一个后台脚本 。后台脚本始终在后台运行,即使加载项的弹出窗口、选项页面或任何其他页面未打开也是如此 。因此,在后台脚本中,我们可以向任何事件添加侦听器并确保它们相应地工作 。
    要添加后台脚本,我们首先需要将其添加到.json:
    "background": {"scripts": ["assets/js/background.js"]}
    一旦我们创建/js/.js并重新加载扩展 , 此脚本将始终在后台运行 。
    我们会监听.js警报响起 。为此,我们需要使用… , 它采用一个函数,该函数将在每次警报触发时执行 。该函数有一个对象作为参数,其中包含有关触发警报的信息 。
    /js/.js使用以下内容创建:
    browser.alarms.onAlarm.addListener((alarmInfo) => {const alarmName = alarmInfo.name.split('_')[0];console.log(alarmName);//TODO send notification});
    我们还通过删除我们附加到它的随机整数来检索警报名称 。然后 , 我们将发送内容为 的通知 。现在 , 我们刚刚TODO发表了评论 。我们还添加了.log用于测试目的 。
    一旦我们重新加载扩展程序,这个后台脚本将开始工作并监听警报 。让我们测试一下 。重新加载扩展程序,然后转到选项页面并添加一个警报,该警报将在一分钟后响起 。接下来,在临时附加组件页面上,单击附加组件的检查按钮 。这将打开一个新窗口,您可以在其中看到控制台 。如果等到警报时间,您将能够在控制台中看到警报的名称 。那是因为我们当前正在侦听警报并在控制台中记录其名称 。
    现在我们有了一个可以工作的后台脚本!下一步是在触发警报时发送通知 。
    发送通知
    要创建和发送通知 , 我们使用..方法 。此方法以及API 中的所有方法 , 只有在.json我们之前已经添加的 中添加权限后才能访问 。
    .. 接受两个参数:
    id:标识通知的字符串 。如果您以后需要更新通知或清除通知 , 这会很有帮助 。如果另一个通知具有相同的id , 则旧的将被新的替换 。如果省略此参数,id将生成一个 。:通知选项的对象 。此对象具有三个必需属性:type、title、 。基于type,将需要一些其他选项 。允许的类型是basic,它只显示扩展图标、标题和消息;image,在通知中显示图像;list,显示项目列表,尽管这主要仅适用于 macOS;和,显示进度条 。
    目前,火狐只支持basic类型,与性质type,title,,和,任选地,,指定该图标的显示 。
    在 中/.js,我们将用TODO以下内容替换注释:
    browser.alarms.onAlarm.addListener((alarmInfo) => {const alarmName = alarmInfo.name.split('_')[0];browser.notifications.create({type: 'basic',title: alarmName,message: 'The alarm you created'});});
    对于标题,我们将显示用户在创建警报时在表单中输入的消息,我们只是添加了一个描述性的.
    返回临时附加组件页面并重新加载扩展程序,然后对其进行测试 。创建带有关闭时间的闹钟,并检查您收到的通知 。
    如果您没有收到任何通知并且您使用的是 macOS,请确保允许来自的通知 。
    删除通知
    我们将添加的最后一个功能是删除通知 。我们将允许用户删除他们从弹出窗口看到的通知,并使用警报名称取消已删除通知的警报 。
    在开始之前,我们将使用 中的垃圾桶图标 。您可以从那里下载它,也可以从本教程的存储库中获取它 。应该在//trash.svg.
    我们需要进行更改以/js/popup.js在每个闹钟的时间旁边显示一个垃圾箱按钮 。我们还将在存储中的数组中使用警报的索引作为元素的 ID,以便以后可以轻松访问它 。
    我们将为被调用添加一个新的可选参数id并显示一个新按钮:
    function appendItem (content, badgeContent = null, id = null) {listElement.append(`
  • ${content}${badgeContent ? `${badgeContent}` : ''}
  • `);}

    然后 , 在循环内,我们将添加index到参数列表中:
    result.alarms.forEach((alarm, index) => {const alarmTime = new Date('1970-01-01T' + alarm.time + 'Z').getTime();if (alarmTime > now) {appendItem(alarm.content, alarm.time, index);}});
    接下来 , 我们将添加一个click事件侦听器.trash-btn,首先从其父级检索警报的索引:
    $('body').on('click', '.trash-btn', function () {const parent = $(this).parents('.alarm-item');const parentId = parent.attr('id');const alarmIndex = parentId.split('_')[1];//TODO delete alarm from alarms array in storage});
    之后,我们将从存储中获取数组,然后使用删除索引处的警报并再次在存储中设置数组:
    //get alarms from storagebrowser.storage.sync.get(['alarms']).then((result) => {let alarms = [];let alarmName = '';if (result.alarms && result.alarms.length > alarmIndex) {alarmName = result.alarms[alarmIndex].alarmName;result.alarms.splice(alarmIndex, 1);}browser.storage.sync.set({alarms}).then(() => {//TODO cancel the alarm});});
    然后 , 我们需要取消闹钟,以免它稍后响起 。为此,我们将使用..clear,它将警报名称作为参数来取消它 。最后,我们将从弹出窗口中删除警报元素:
    //remove alarm by namebrowser.alarms.clear(alarmName);//remove alarm item from listparent.remove();
    有了这个,我们添加了一个删除功能,可以从存储中删除警报,并取消它在后台关闭 。
    让我们为刚刚添加的按钮添加一些样式 。创建/css/popup.css包含以下内容的文件:
    .trash-btn {background-color: transparent;border: none;}.trash-btn img {width: 15px;height: 15px;}
    然后将此样式表添加到popup.html:

    现在检查弹出窗口 。它应该是这样的:
    尝试添加应该在接下来的几分钟内发送通知的闹钟 。然后将其删除 。在您安排的时间不应发出警报 。
    就是这样!我们创建了一个扩展,用于在sync存储中存储用户的信息,然后我们学习了如何创建以特定时间间隔触发的警报 。然后我们创建了一个后台脚本来侦听警报触发,最后我们学习了如何在侦听警报触发后向用户发送通知 。
    创建附加组件生命周期的下一步是在的 Hub上发布它 。
    发布插件
    现在我们已准备好发布附加组件,我们可以删除 中的tings密钥.json,因此请务必先执行此操作 。
    您需要登录您的帐户,或创建一个新帐户 。你可以在这里做到这一点 。
    登录后,您可以看到“我的附加组件”部分 。单击右下角的提交新加载项按钮 。
    然后将开始提交新附加组件的过程 。首先会询问您是在附加组件管理器上发布附加组件,还是自行分发 。选中第一个默认选项,然后单击 。
    接下来,系统会要求您上传扩展程序 。为此,请转到您在其中创建附加组件的目录,并创建一个包含所有内容的压缩 ZIP 文件 。确保加载项的根目录是 ZIP 文件的根目录,这意味着它.json应该在 ZIP 文件的根目录中 。然后上传该 ZIP 文件 。您还可以选择让插件可用于。
    注意:如果您收到错误“发现重复的附加组件 ID”,请确保您tings已从.json.
    文件上传且没有错误后,点击 。
    在下一步中,您将被要求指定您的附加组件是否使用任何编译器或压缩器或任何对附加组件代码进行任何处理的工具 。这背后的原因是将需要您提交原始代码以供审核 。由于我们的附加组件不使用任何这些工具,只需选中No并单击 。
    在最后一步中,系统会要求您输入有关附加组件的一些信息 。任何想要安装您的附加组件的用户都会看到此信息 , 因此请确保使其尽可能清晰和具有描述性 。输入加载项的名称、描述、类别等 。完成后,单击。如果您尚未准备好填写某些信息,请不要担心,因为您可以稍后对其进行编辑 。
    就是这样!单击后,您的附加组件将等待审核,这不会花费很长时间 。审核过程最多可能需要一天时间 。一旦获得批准,您将收到一封电子邮件通知 , 然后您可以在商店中查看该插件 。您还可以转到附加组件的信息页面并添加或编辑任何信息 , 例如其说明、图像等 。
    更新附加组件也很容易 。您只需上传更新的版本,即可立即使用!这使得在上发布附加组件比大多数其他浏览器更容易、更快 。
    使附加组件与兼容
    为了使我们刚刚创建的扩展与兼容,我们需要进行以下修改:
    替换所有出现的.*用.* 。在上,它的所有 API 都使用回调而不是返回承诺 。这意味着我们不需要在我们的代码中使用,而是需要传递一个回调函数作为最后一个参数 。
    进行这些更改的一个示例是/js/.js. 我们使用以下代码来获取警报并显示它们:
    browser.storage.sync.get(['alarms']).then((result) => {//...});
    我们将用以下代码替换此代码:
    chrome.storage.sync.get(['alarms'], (result) => {//...});
    就是这样 。我们只是将其余的代码移到回调函数中 。
    结论
    在本教程中,我们讨论了如何创建具有基本和必要功能的附加组件,例如使用存储、发送通知、创建后台脚本等 。了解如何完成所有这些可以帮助您创建具有许多功能的附加组件 。开始创造一些很棒的东西!
    【在 Firefox 中加载附加组件】本文到此结束,希望对大家有所帮助 。