chrome 插件开发入门

1. 介绍

Chrome 插件可用于在谷歌浏览器上控制当前页面的一些操作,可自主控制网页,提升效率。

平常我们可在谷歌应用商店中下载谷歌插件来增强浏览器功能,作为开发者,我们也可以自己开发一个浏览器插件来配合我们的日常学习工作,提升幸福感。

谷歌插件开发者官网,可以阅读插件开发文档来写插件,插件开发主要是 JavaScript,因此对前端开发者很友好

2. 快速入门

2.1 manifest.json 配置

  1. 新建一个文件夹,就叫 ChromePlugin

  2. 在 ChromePlugin 根目录下新建 manifest.json 文件

manifest 文件是插件的配置文件,只有在该 json 文件中增加了配置项,才允许增加自定义的内容,下面是常见的 json 文件配置

js 复制代码
{
    "manifest_version": 3,
    "name": "chromePlugin",
    "version": "1.0.0",
    "description": "我的第一个谷歌插件",
    "icons": {
        "16": "./assets/images/icon16.png",
        "32": "./assets/images/icon32.png",
        "48": "./assets/images/icon48.png",
        "128": "./assets/images/icon128.png"
    },   
}

基本配置:

  • manifest_version:manifest 的版本,是谷歌针对插件开发的版本配置,目前主流都是 3 版本,2 版本已经停止更新
  • name:插件的名称,即插件在谷歌商店以及使用时的名称
  • version:插件的版本
  • description:插件的描述信息
  • icons:描述插件图标的大小和文件路径,目前提供 4 种规格的图片,按照上述配置分别传入不同大小的图片即可,图片地址可在根目录下创建一个 assets文件放置静态资源

其他配置可见下文中的详细解释

到这里,一个 chrome 插件已经可以被加载出来了

打开谷歌浏览器,输入 chrome://extensions ,启用开发者模式 (右上角),再点击「加载已解压的扩展程序」然后找到 ChromePlugin 这个文件夹打开,便可以将这个插件加载进来了,只不过当前插件没有任何功能,所以也是灰色的

2.2 action 配置

在 manifest.json 中除了上述的基础配置外,还可配置 action,action 字面上意思就是我们点击右上角的插件图标时的反应,比如打开一个交互面板等等。这种交互的集合就是 action。

首先先在 manifest.json 中配置 action,可见官网针对 action 的配置信息,action配置

default_popup 可在点击插件图片时弹出一个弹层,弹层的内容就是 default_popup 所对应的 html 文件。

json 复制代码
{
    "manifest_version": 3,
    "name": "chromePlugin",
    "version": "1.0.0",
    "description": "我的第一个谷歌插件",
    "icons": {
        "16": "./assets/images/icon16.png",
        "32": "./assets/images/icon32.png",
        "48": "./assets/images/icon48.png",
        "128": "./assets/images/icon128.png"
    },
    "action": {
        "default_title": "Click Me",
        "default_popup": "./action/index.html",
        "default_icon": "./assets/images/icon32.png"
    }    
}

可在根目录下新建一个 action 文件夹,然后再创建一个 index.html 文件,写一个简单的测试文件

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .hello {
            width: 100px;
        }
    </style>
</head>
<body>
    <div class="hello">hello simon</div>
  	<script src="./index.js"></script>
</body>
</html>

再次加载该插件,点击插件图标,可在图标下方看到一个弹层,弹层显示的是 html 文件中的内容

如果想写 js 代码,不能直接在 html 中创建一个 script 标签,然后写代码,插件中不允许 html 中有内联脚本,因此需要将脚本代码作为一个单独的文件,再通过 script 标签来引入

2.3 content_scripts

如果我们想给插件添加功能,那就需要再配置 content_scripts(内容脚本),插件content_scripts

不是所有的 chrome 的 api 方法都能在 content_scripts 中使用
content_scripts 的特性:

  • 可在页面打开、或页面加载结束、或者页面空闲时注入

  • 共享页面的 dom,因此脚本文件可以操作页面上的 dom

  • JS 隔离,脚本文件的 js 不会影响到页面中的 js,也无法引用页面 js 中的函数或变量

content_scripts 的注入方式也有多种:静态注入、动态注入、编码注入

  • 静态注入,即在 manifest.json 文件中指定 content_scripts 中的 js 文件,比较常用
  • 动态注入,通过 chrome.scripting.registerContentScripts 方法注入
  • 编码注入,通过 chrome.scripting.executeScript

在 manifest.json 中可传入的属性

属性 类型 描述
matches 字符串数组 必填,指定将内容脚本注入到哪些网页
css 字符串数组 可选,要注入到匹配页面的 css 文件
js 字符串数组 可选,要注入到匹配页面的 js 文件
run_at document_start |document_end |document_idle 可选,指定何时将脚本注入到网页中,默认值document_idle document_idle: 页面空闲时 document_end:在dom完成之后,图片等资源加载前注入脚本 document_start:在dom完成前就注入脚本

在 manifest.json 中配置 content_scripts

json 复制代码
{
    "manifest_version": 3,
    "name": "chromePlugin",
    "version": "1.0.0",
    "description": "我的第一个谷歌插件",
    "icons": {
        "16": "./assets/images/icon16.png",
        "32": "./assets/images/icon32.png",
        "48": "./assets/images/icon48.png",
        "128": "./assets/images/icon128.png"
    },
    "action": {
        "default_title": "Click Me",
        "default_popup": "./action/index.html",
        "default_icon": "./assets/images/icon32.png"
    }, 
    "content_scripts": [
      {
        "matches": ["https://*/*"],
        "css": ["./src/index.css"],
        "js": ["./src/main.js"]
      }
    ]
}
js 复制代码
// 计算图片大小
function getByte(src){
    return fetch(src).then(function(res){
        return res.blob()
      }).then(function(data){
        return (data.size/(1024)).toFixed(2)+'kB';
      })
}
// 在页面上的图片的title属性上显示出来
function showInfo(el,byte){
    const html=`真实尺寸:${el.naturalWidth}*${el.naturalHeight}\n显示尺寸:${el.width}*${el.height}\n存储大小:${byte}`;
    el.title=html;
}
document.addEventListener('mouseover',function(e){
    //移动到图片元素上时、则显示信息
    if(e.target.tagName=='IMG'){
        getByte(e.target.src).then(byte=>{
            showInfo(e.target,byte)
        });
    }
},true)

2.4 background

配置后台脚本,用于处理插件的主要事件的处理,后台脚本指定了属性 service_worker,其实后台脚本是 Service Worker 上处理的。我们插件上的一些主要逻辑的处理都可以放到这个脚本文件中

json 复制代码
{
    "manifest_version": 3,
    "name": "chromePlugin",
    "version": "1.0.0",
    "description": "我的第一个谷歌插件",
    "icons": {
        "16": "./assets/images/icon16.png",
        "32": "./assets/images/icon32.png",
        "48": "./assets/images/icon48.png",
        "128": "./assets/images/icon128.png"
    },
    "action": {
        "default_title": "Click Me",
        "default_popup": "./action/index.html",
        "default_icon": "./assets/images/icon32.png"
    }, 
    "content_scripts": [
      {
        "matches": ["https://*/*"],
        "css": ["./src/index.css"],
        "js": ["./src/main.js"]
      }
    ],
  	"background": {
        "service_worker": "./src/server_worker.js"
    }
}

2.5 右键菜单

当我们点击鼠标右键时,可打开一个菜单,其中有复制粘贴等功能,插件也可以自定义右键的菜单,同样需要在 manifest.json 中添加权限配置

json 复制代码
{
    "manifest_version": 3,
    "name": "chromePlugin",
    "version": "1.0.0",
    "description": "我的第一个谷歌插件",
    "icons": {
        "16": "./assets/images/icon16.png",
        "32": "./assets/images/icon32.png",
        "48": "./assets/images/icon48.png",
        "128": "./assets/images/icon128.png"
    },
    "action": {
        "default_title": "Click Me",
        "default_popup": "./action/index.html",
        "default_icon": "./assets/images/icon32.png"
    }, 
    "content_scripts": [
      {
        "matches": ["https://*/*"],
        "css": ["./src/index.css"],
        "js": ["./src/main.js"]
      }
    ],
  	"permissions": ["contextMenus"]
}

permissions 是允许增加权限配置,右键菜单就是一种权限配置,开启右键菜单权限后,需要再通过代码新增右键的菜单,这个时候就需要用到上一步的 background 中的配置了

在 service_worker.js 文件中新增一个右键菜单,可使用 chrome.contextMenus.create 方法来创建

js 复制代码
chrome.contextMenus.create({
    type: 'normal',
    title: '插件的右键菜单',
    contexts:['all'],
    id:'menu-1'
});

保存后,就能在右键看到一个菜单选项了

2.6 permissions

在上一步创建的右键菜单中,涉及到权限设置,只有在 permissions 添加了对应权限后,才允许去创建菜单,权限除了右键菜单外,还有其他的权限,权限列表,常见的有:

当涉及到权限问题时,就需要先在 permissions 添加了对应权限后,才允许使用 chrome.xxx 再使用对应的功能。

2.7 options

options 就是选项页面,可用于在插件的右键选项中进行配置跳转,也可以在插件管理页面点击详情后打开插件选项,当增加该配置项后,选中插件再右键时,会增加一个「选项」的菜单,点击后会跳转到配置的页面。要展示该选项需要在 manifest.json 中配置 options_ui

json 复制代码
{
    "manifest_version": 3,
    "name": "chromePlugin",
    "version": "1.0.0",
    "description": "我的第一个谷歌插件",
    "icons": {
        "16": "./assets/images/icon16.png",
        "32": "./assets/images/icon32.png",
        "48": "./assets/images/icon48.png",
        "128": "./assets/images/icon128.png"
    },
    "action": {
        "default_title": "Click Me",
        "default_popup": "./action/index.html",
        "default_icon": "./assets/images/icon32.png"
    }, 
    "content_scripts": [
      {
        "matches": ["https://*/*"],
        "css": ["./src/index.css"],
        "js": ["./src/main.js"]
      }
    ],
  	"permissions": ["contextMenus"],
  	"options_page": "./options/index.html", // chrome40 之前的写法
  	"options_ui": { // chrome40 之后的写法
      "page": "./options/index.html",
      "chrome_style": true // 添加一些默认样式
    }
}
html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>这是 options 点击后打开的页面</div>
</body>
</html>

3. 页面通信

在 manifest.json 中可通过不同配置来实现插件的扩展能力,比如 content_scripts、background、options、actions 都有脚本文件,那如何在不同的脚本文件中传递数据呢,比如在 content_scripts 是在网页中运行的,其中的数据如何共享给 background,可以通过页面通信来传递数据。

官网文档

3.1 发送数据

js 复制代码
// 从内容脚本 content_scripts 发送数据到扩展页面(background、options、actions)
(async () => {
  const response = await chrome.runtime.sendMessage({greeting: "hello"});
  console.log(response);
})();
JS 复制代码
// 从扩展页面(background、options、actions) 发送数据到内容脚本(content_scripts)
(async () => {
    // 需要先获取当前的tab页面
  const [tab] = await chrome.tabs.query({active: true, lastFocusedWindow: true});
  const response = await chrome.tabs.sendMessage(tab.id, {greeting: "hello"});
  console.log(response);
})();

不同的发送方,发送数据的方式也是不同的,在使用时需要有所区别

3.2 接收数据

接收数据的方式是一致的,都是通过 chrome.runtime.onMessage

js 复制代码
// 接收数据
chrome.runtime.onMessage.addListener(
  (request, sender, sendResponse) => {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.greeting === "hello")
      //处理完消息后、通知发送方
      sendResponse({farewell: "goodbye"});
  }
);
相关推荐
树上有只程序猿13 分钟前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼1 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
黄毛火烧雪下1 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox1 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞1 小时前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行1 小时前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox
m0_593758101 小时前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox
掘金一周1 小时前
金石焕新程 >> 瓜分万元现金大奖征文活动即将回归 | 掘金一周 4.3
前端·人工智能·后端
三翼鸟数字化技术团队2 小时前
Vue自定义指令最佳实践教程
前端·vue.js
Jasmin Tin Wei2 小时前
蓝桥杯 web 学海无涯(axios、ecahrts)版本二
前端·蓝桥杯