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"});
  }
);
相关推荐
永乐春秋1 小时前
WEB攻防-通用漏洞&文件上传&js验证&mime&user.ini&语言特性
前端
鸽鸽程序猿1 小时前
【前端】CSS
前端·css
ggdpzhk1 小时前
VUE:基于MVVN的前端js框架
前端·javascript·vue.js
学不会•3 小时前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
活宝小娜5 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点5 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow5 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o5 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
开心工作室_kaic6 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā6 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue