最近学习了Chrome插件的开发,总体来说上手还是很容易的,因为浏览器插件本质上依旧是网页,写几个demo基本就了解了他的开发过程。

什么是Chrome插件

正如开头所说的,Chrome插件实际上就是一个网页,由HTML、CSS、JS、图片等资源组成,与网页不同的是,Chrome插件是用来增强浏览器功能的,同时它还有一套属于自己的开发规则和API。

每个插件都由不同的组件构成,这些组件大都包括background scripts,content scripts,options page,UI以及各种逻辑文件,当然,这些文件是否需要是根据插件的功能所决定的。

接下来我将通过开发一个获取页面图片并保存的插件来介绍如何开发一个Chrome插件。

获取页面上的图片

首先,我们需要一个目录来存放这个插件的各个文件。

创建manifest

manifest.json是一个Chrome插件必不可少的文件,它包含了你插件的所有信息。

{
"name": "获取图片",
"description": "获取页面上的所有图片",
"version": "1.0",
"manifest_version": 3
}

只要在目录中包含manifest.json,这个目录就可以被作为一个Chrome插件添加到Chrome当中。

  1. 在浏览器地址栏中输入chrome://extensions,回车以打开浏览器的扩展程序界面
  2. 打开开发人员模式
  3. 点击加载已解压的扩展程序,选择manifest文件所在的目录

这样我们就成功安装了一个扩展,接下来我们要在此基础上完善它。

用户界面

一个插件可以有多种形式的用户界面,这里我们选择弹出层作为用户界面,在插件根目录下创建一个popup.html,这个页面需要包含两个按钮分别用来触发获取图片和保存图片的事件,以及一个用来展示图片的盒子。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<style>
body,
img {
width: 400px;
}
</style>
</head>
<body>
<button id="get">获取</button>
<button id="save">保存</button>
<div id="app"></div>
</body>
</html>

注意,如果在popup.html中有中文出现,一定要在head标签中添加<meta charset="UTF-8" />,以防止出现乱码。

创建完成后,我们需要在manifest.json中声明该页面,以保证浏览器能够正确的读取到它。添加一个action对象,同时将popup.html设置为该对象的default_popup

{
"name": "获取图片",
"description": "获取页面上的所有图片",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_popup": "popup.html",
},
}

为了让我们的插件像个正经的插件,给他添加上图标。我们需要准备16x16、32x32、48x48以及128x128四种大小的图标图片,将它们放到目录中,之后将它们的路径写入manifest.json中。

{
"name": "获取图片",
"description": "获取页面上的所有图片",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "/images/logo16.png",
"32": "/images/logo32.png",
"48": "/images/logo48.png",
"128": "/images/logo128.png"
}
},
}

为了让图标能够在扩展程序管理页面显示,我们还需要添加一个icons对象。

{
"name": "获取图片",
"description": "获取页面上的所有图片",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "/images/logo16.png",
"32": "/images/logo32.png",
"48": "/images/logo48.png",
"128": "/images/logo128.png"
}
},
"icons": {
"16": "/images/logo16.png",
"32": "/images/logo32.png",
"48": "/images/logo48.png",
"128": "/images/logo128.png"
}
}

点击扩展程序管理页面中的更新按钮,即可看到添加完用户界面的插件信息了。

功能逻辑

之后我们要为插件添加它应有的功能——获取页面图片。

首先我们先简单梳理一下需求:

  1. 点击popup.html中的获取按钮,拿到当前页面的图片
  2. 点击popup.html中的保存按钮,将拿到的图片保存下来

实际上我们的插件与当前正在活动的页面并不是同一个页面,因此我们需要通过某种方式来将获取图片的js代码发送到当前活动页上,并且还需要这段js代码能够在获取到图片之后将图片发送到popup.html中。

这里我们就需要用到一开始提到的content scripts组件以及content script与popup之间通信的API。content scripts简单来说就是插入页面的脚本,虽说是插入页面的脚本,实际上它与页面原本的js是分割开的,双方不能获取到对方的变量、函数等内容。不过content scripts还是可以获取到dom的。

获取图片

首先添加一个content-script.js,这个脚本主要有两个功能,一是获取图片,二是监听popup传来的消息,然后将获取到的图片作为回信传回去。

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
// message的数据格式取决于发送时的数据
const { start } = message; if (start) {
const images = document.getElementsByTagName('img');
const imgSrcList = Array.from(images).map((img) => img.src);
sendResponse(imgSrcList);
}
});

之后我们要在manifest.json中声明配置它

{
...
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"js/content-script.js"
]
}
]
}

matches声明了content scripts要注入的页面,<all_urls>表示所有页面,js属性声明了要注入的js脚本,除此之外还有css属性声明要注入的css代码、run_at属性声明注入时机等都可以在官方文档中找到。

之后添加一个popup.js为界面上的按钮注册点击事件,并在popup.html中引入它

let srcList;
const getImageBtn = document.getElementById('get'); getImageBtn.addEventListener('click', async () => {
// 获取当前活动页
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
let message = { start: true };
// 向content scripts发送消息
chrome.tabs.sendMessage(tab.id, message, (res) => {
srcList = Array.from(new Set(res));
// popup中展示图片
const imgList = srcList.map((src) => `<img src="${src}" />`).join(''); document.getElementById('app').innerHTML = imgList;
});
});
}); const saveImageBtn = document.getElementById('save'); saveImageBtn.addEventListener('click', () => {
// 保存图片
});
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<style>
body,
img {
width: 400px;
}
</style>
</head>
<body>
<button id="get">获取</button>
<button id="save">保存</button>
<div id="app"></div>
<script src="./js/popup.js"></script>
</body>
</html>

这里我们需要注意,插件要想和当前活动页面通信就需要首先获取它的tabId,而要获取当前活动页面的tabId则需要给予插件对应的权限,因此我们需要在manifest.json中声明所需要的权限。

{
...
"permissions": [
"activeTab"
]
}

完成后更新一下插件,然后打开想要获取图片的页面点击获取按钮即可(如果页面已经提前打开请刷新一下)

保存图片

js可以通过a标签设置href和download属性来实现批量保存图片,但是这里我们要通过调用chrome的download API来实现。

...

saveImageBtn.addEventListener('click', () => {
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
if (!srcList) {
document.getElementById('app').innerHTML = '未获取图片';
return;
} srcList.forEach((src) => {
chrome.downloads.download({
url: src,
});
});
});
});

与获取活动页面相同,download API同样也需要获取权限

{
...
"permissions": [
"activeTab",
"downloads"
]
}

这样一个获取当前页面图片的插件就完成了。

参考文章

Chrome插件开发入门的更多相关文章

  1. Chrome插件开发入门(二)——消息传递机制

    Chrome插件开发入门(二)——消息传递机制   由于插件的js运行环境有区别,所以消息传递机制是一个重要内容.阅读了很多博文,大家已经说得很清楚了,直接转一篇@姬小光 的博文,总结的挺好.后面附一 ...

  2. [Chrome插件开发]001.入门

    Chrome插件开发入门 Chrome扩展文件 Browser Actions(扩展图标) Page Actions(地址栏图标) popup弹出窗口 Background Pages后台页面 实战讲 ...

  3. vue.js 初体验— Chrome 插件开发实录

    欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 作者:陈纬杰 背景 对于经常和动画开发打交道的开发者对于Animate.css这个动画库不会陌生,它把一些常见 ...

  4. chrome插件开发-消息机制中的bug与解决方案

    序言 最近开发chrome插件,涉及到消息传递机时按照教程去敲代码,结果总是不对.研究了大半天终于找到原因,现在记录下. 程序 插件程序参考官网 chrome官网之消息传递机制, 不能FQ的同事也可以 ...

  5. Chrome插件开发,美化网页上的文件列表。chrome-extension,background

    上一篇文章 通过“content-scripts”的方式向页面注入js和css来美化页面,但是有一个弊端:一旦配置好需要注入的页面,之后如果这个页面地址以后发生变化,或者要新加一些URL进来,那么得修 ...

  6. Chrome插件开发,美化网页上的文件列表。chrome-extension,content-scripts

    趁着2018年还剩最后几天,发几篇博客,荒废太久了,惭愧. 最近也是需求驱动,研究了下Chrome插件开发.来看一下我们公司运维提供的日志查看页面 所有项目的日志都参杂在一起,每次去找都很痛苦.慢慢发 ...

  7. chrome插件开发学习(一)

    两个不错的网址: 360chrome插件开发文档:http://open.chrome.360.cn/extension_dev/manifest.html 图灵 chrome插件开发于应用 电子书: ...

  8. 入门chrome插件开发教程和经验总结,一篇就搞掂!

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_44244857/articl ...

  9. Vue插件开发入门

    相对组件来说,Vue 的插件开发受到的关注要少一点.但是插件的功能是十分强大的,能够完成许多 Vue 框架本身不具备的功能. 大家一般习惯直接调用现成的插件,比如官方推荐的 vue-router.vu ...

随机推荐

  1. .NET微服务最佳实践 eShopOnContainers

    本文翻译自微软Docs, 内嵌译者多年使用的参悟,如理解有误,请不吝赐教. 微软与社区专家合作,开发了功能齐全的云原生微服务示例应用eShopOnContainers. 该应用旨在展示使用.NET.D ...

  2. 教你玩转CSS Position(定位)

    CSS Position(定位) position 属性指定了元素的定位类型. position 属性的五个值: static relative fixed absolute sticky 元素可以使 ...

  3. js中this指向的问题与联系

    前言 JavaScript 中最大的一个安全问题,也是最令人困惑的一个问题,就是在某些情况下this的值是如何确定的.有js基础的同学面对这个问题基本可以想到:this的指向和函数调用的方式相关.这当 ...

  4. 第28天学习打卡(Date和Calendar类 基本类型的包装类 集合 增强for循环 )

    Date和Calendar类 简介 日期和日历类,用于操作日期相关信息. 构造方法 Date(): 构造一个日期对象,当前系统时间,精确到毫秒. Date(long): 构造一个日期对象,时间为自&q ...

  5. python爬虫模拟登录验证码解决方案

    [前言]几天研究验证码解决方案有三种吧.第一.手工输入,即保存图片后然后我们手工输入:第二.使用cookie,必须输入密码一次,获取cookie:第三.图像处理+深度学习方案,研究生也做相关课题,就用 ...

  6. System.IO.IOException:“找不到资源“window1.xaml”。” 解决方法

    报错:找不到资源"window1.xaml 原因:在编译时使用的是en-US选项进行编译并生成了en-US为名的文件夹,里面包含了可本地化的内容:但是你的本地系统使用的是zh-CN,在你运行 ...

  7. LeetCode-层数最深叶子结点的和

    层数最深叶子结点的和 LeetCode-1302 这里可以采用上一题中求解二叉树的深度的方法. 因为需要记录最深结点的值的和,所以这里可以边求和,如果遇到不符合最深结点时再将和sum=0. /** * ...

  8. linux进程隐藏手段及对抗方法

    1.命令替换 实现方法 替换系统中常见的进程查看工具(比如ps.top.lsof)的二进制程序 对抗方法 使用stat命令查看文件状态并且使用md5sum命令查看文件hash,从干净的系统上拷贝这些工 ...

  9. PTA1071 - Speech Patterns - map计算不同单词个数

    题意 输出给定字符串出现最多的字符串(小写输出)和出现次数. 所求字符串要求:字符中可以含有A-Z.0-9. 比如说题目给出的Can1,我们可以转换成can1,can1就算一个字符串整体,而不是单独的 ...

  10. 从零学脚手架(五)---react、browserslist

    如果此篇对您有所帮助,在此求一个star.项目地址: OrcasTeam/my-cli react react介绍 目前,国内主流的前端应用框架具有两个:vue.js和react.js,关于vue和r ...