从零到一开发一个Chrome插件(三)

引言

大家好啊,我是前端拿破轮。

作为一个前端工程师,Chrome在我们的工作中扮演着重要作用。它不仅是前端的主要运行环境,而且是我们代码调试的重要工具,也是平时学习生活使用的重要软件。

在Chrome中有许多优秀的扩展,包括但不限于我们使用的React Devtools沉浸式翻译插件等等。许多扩展极大地拓展了浏览器的能力边界,提高了我们工作和学校的效率。

所以笔者早有开发一个自己的插件的想法,苦于之前一直忙于学习和工作,没有合适的时间,最近忙里偷闲,决定抽出时间来进行这项工作。而且AI的时代浪潮也给浏览器的插件带来了新的生命力。所以笔者决定做一款浏览器端的AI助手插件。

本文属于Chrome插件开发专栏,会持续更新拿破轮的Chrome插件开发过程,欢迎各位读者订阅,希望对你有所帮助。如果还没有看过之前文章的读者,可以先阅读专栏中前面的文章。

专注模式Demo

需求目标:点击扩展程序工具栏图标,简化当前网页样式,进入专注模式

概述

本文将构建一个扩展程序,用于简化Chrome扩展程序和Chrome应用商店文档页面的样式,以便用户更轻松地阅读。

在本文中,我们将介绍如何执行以下操作:

  • 将扩展程序Service Worker用作事件协调者
  • 通过activeTab权限保护用户隐私
  • 在用户点击扩展程序工具栏图标时运行代码
  • 使用Scripting API插入和移除样式表
  • 使用键盘快捷键执行代码

第 1 步:初始化扩展程序

这里为了方便,我们直接在本专栏之前文章的基础上进行修改,不再新建插件文件夹,没有看过之前文章的读者可以先看前面的文章。

扩展程序可以使用Service Worker来监控浏览器事件。Service Worker是一种特殊的JavaScript环境,用于处理事件,并在不需要时终止。

首先,在manifest.json中注册Service Worker

json 复制代码
 // manifest.json
 ​
 {
   ...
   "background": {
     "service_worker": "background.js"
   }
   ...
 }

创建一个background.js文件在根目录,并添加以下代码:

arduino 复制代码
 // background.js
 chrome.runtime.onInstalled.addListener(() => {
   chrome.action.setBadgeText({
     text: 'OFF',
   });
 });

我们的Service Worker将监听的第一个事件是runtime.onInstalled()。借助此方法,扩展程序可以在安装时设置成初始状态或完成一些任务。扩展程序可以使用 Storage APIIndexedDB 存储应用状态。不过,在本例中,由于我们只处理两种状态,因此将使用操作图标本身来追踪扩展程序是处于"开启"还是"关闭"状态。

操作图标指的是工具栏扩展操作中的扩展图标

第 2 步:启用扩展程序操作

当我们在Chrome的扩展工具栏中点击扩展图标时,它将运行一些代码或者弹出一个弹窗。我们可以在manifest.json中添加以下代码来声明扩展操作。

json 复制代码
 // manifest.json
 {
   ...
   "action": {
     "default_icon": {
       "16": "images/icon-16.png",
       "32": "images/icon-32.png",
       "48": "images/icon-48.png",
       "128": "images/icon-128.png"
     }
   }
   ...
 }

使用activeTab权限保护用户隐私

activeTab权限可授予扩展程序在有效标签页上执行临时代码的权限。它还允许访问当前标签页的敏感属性

当用户调用扩展程序时,系统会启用此权限。在这种情况下,用户通过点击扩展程序图标来调用扩展程序。

用户的以下互动会启用activeTab权限

  • 按键盘快捷键组合
  • 选择上下文菜单项
  • 接收Omnibox中的建议
  • 打开扩展程序弹出式窗口

借助activeTab权限,用户可以有目的地选择在聚焦的标签页上运行扩展程序;这样一来,就可以保护用户的隐私,而且这种方式运行扩展程序也不会触发权限警告

我们要想使用activeTab权限,需要将其添加到manifest.json的权限数组中。

json 复制代码
 {
   ...
   "permissions": ["activeTab"],
   ...
 }

第 3 步:跟踪当前标签页的状态

用户点击扩展程序后,该扩展程序会检查网址是否与文档页面匹配。接下来,它会检查当前标签页的状态并设置下一个状态。我们需要将以下代码添加到background.js

ini 复制代码
 const extensions = 'https://developer.chrome.com/docs/extensions';
 const webstore = 'https://developer.chrome.com/docs/webstore';
 ​
 chrome.action.onClicked.addListener(async (tab) => {
   if (tab.url.startsWith(extensions) || tab.url.startsWith(webstore)) {
     // 获取扩展图标,以检查扩展当前是否开启
     const prevState = await chrome.action.getBadgeText({ tabId: tab.id });
 ​
     // 写一个状态
     const nextState = prevState === 'ON' ? 'OFF' : 'ON';
 ​
     // 设置下一个状态
     await chrome.action.setBadgeText({
       tabId: tab.id,
       text: nextState,
     });
   }
 });

第 4 步:添加或移除样式表

创建一个名为focus-mode.css的文件,并写入下面的代码

css 复制代码
 * {
   display: none !important;
 }
 ​
 html,
 body,
 *:has(article),
 article,
 article * {
   display: revert !important;
 }
 ​
 [role='navigation'] {
   display: none !important;
 }
 ​
 article {
   margin: auto;
   max-width: 700px;
 }

我们要想应用这个样式表,需要使用Scripting API来插入或移除样式表。

首先,我们需要再manifest.json中声明script权限。

json 复制代码
 {
   ...
   "permission": ["activeTab", "scripting"],
   ...
 }

最后,在background.js中修改为如下代码。

php 复制代码
 // 等待扩展完全初始化
 chrome.runtime.onInstalled.addListener(() => {
   // 显式检查 chrome.action 是否存在
   if (chrome.action) {
     chrome.action.setBadgeText({ text: 'OFF' });
   } else {
     console.error('chrome.action API 不可用');
   }
 });
 ​
 const extensions = 'https://developer.chrome.com/docs/extensions';
 const webstore = 'https://developer.chrome.com/docs/webstore';
 ​
 chrome.action.onClicked.addListener(async (tab) => {
   if (tab.url.startsWith(extensions) || tab.url.startsWith(webstore)) {
     // 获取扩展图标,以检查扩展当前是否开启
     const prevState = await chrome.action.getBadgeText({ tabId: tab.id });
 ​
     // 写一个状态
     const nextState = prevState === 'ON' ? 'OFF' : 'ON';
 ​
     // 设置下一个状态
     await chrome.action.setBadgeText({
       tabId: tab.id,
       text: nextState,
     });
 ​
     if (nextState === 'ON') {
       // 插入 CSS 文件
       await chrome.scripting.insertCSS({
         files: ['focus-mode.css'],
         target: { tabId: tab.id },
       });
     } else if (nextState === 'OFF') {
       // 移除 CSS 文件
       await chrome.scripting.removeCSS({
         files: ['focus-mode.css'],
         target: {
           tabId: tab.id,
         },
       });
     }
   }
 });

Scripting API不仅可以插入和移除 CSS,也可以使用scripting.executeScript()来注入JavaScript

第 5 步:分配键盘快捷键

commands键添加到manifest.json文件中。

json 复制代码
{
  ...
  "commands": {
    "_execute_action": {
      "suggested_key": {
        "default": "Ctrl+B",
        "mac": "Command+B"
      }
    }
  }
  ...
}

_execute_action按键会运行与action.onClicked事件相同的代码,因此无需额外的代码。

测试效果

首先,打开以下任一页面:

我们以第一个页面为例,打开后如下图所示:

我们可以看到插件此时是OFF状态,网页是正常模式。

我们点击插件 ,或者使用刚才设置的快捷键 Ctrl+BmacCommand+B),发现网页应用了我们的CSS样式文件,进入了专注模式,插件状态也面成了ON

总结

本文我们通过配置内容脚本,实现了在专注模式的Demo,知道了如何插入和移除样式表,并且进行了快捷键的配置。

本文属于Chrome插件开发专栏,会持续更新拿破轮的Chrome插件开发过程,欢迎各位读者订阅,希望对你有所帮助。

好了,这篇文章就到这里啦,如果对您有所帮助,欢迎点赞,收藏,分享👍👍👍。您的认可是我更新的最大动力。由于笔者水平有限,难免有疏漏不足之处,欢迎各位大佬评论区指正。

往期推荐✨✨✨

我是前端拿破轮,关注我,一起学习前端知识,我们下期见!

相关推荐
94very18 小时前
iframe实践
前端
用户857594145002918 小时前
产品让你写段炫彩炫酷的字体效果,你该怎么做?回答我?
前端
南北是北北18 小时前
Flow 热流
前端·面试
一只小风华~18 小时前
快速搭建一个Vue+TS+Vite项目
前端·javascript·vue.js·typescript·前端框架
m0_7381207218 小时前
CTFshow系列——命令执行web73-77(完结篇)
前端·安全·web安全·网络安全·ctfshow
呵阿咯咯18 小时前
前端开发典型问题解决方案:打包冲突、状态更新与性能优化
前端
前端搬运侠18 小时前
🚀 浏览器原理+网络知识面试必刷!50道高频面试题详解
前端
励扬程序18 小时前
Cloudflare workers 构建和部署无服务器功能、站点和全栈应用程序。
前端·全栈
YUJIANYUE18 小时前
纯前端html英文字帖图片生成器自动段落和换行
前端·html