Chrome 扩展插件开发
# Chrome 扩展插件开发
# 1、基础介绍
扩展程序是定制浏览体验的小型软件程序。这些扩展程序能够使得用户根据个人需求或者偏好定制 Chrome 功能和行为。基于 HTML, JavaScript和 CSS 等 Web 技术构建。
扩展程序由不同的组件构成,这些组件包含以下几种:
- background scripts (运行在后台的脚本)
- content scripts (运行在页面的逻辑脚本)
- options page (页面)
- ui elements (UI元素)
- 各种逻辑组件
# 1.1 基础结构
Chrome 的扩展程序必须有一个manifest.json文件,文件用来描述APP信息以及其他资源加载路径,需要最基本的四个信息就可以实现一个hello-word扩展插件
manifest.json
{
"name":"hello-word",
"description":"你好,扩展插件",
"version":"1.0",
"manifest_version":2
}
2
3
4
5
6
7
8
浏览器加载已解压的扩展程序,如图所示,已经完成了一个最基础的扩展插件
# 1.2 声明browser_action
popup
"default_popup":"popup.html"
在点击插件的时候会弹出弹框,弹框内容就是popup.html的内容,popup的内容在点击浏览器空白处会自动关闭
icon
"default_icon":"hello.png"
插件展示的默认图标
# 1.3 commands 快捷键
commands属性用来配置快捷键 ,例如可以配置快捷键来直接唤醒程序,
{ "commands":{ "_execute_browser_action":{ //用来执行browser_action中的设置 "suggested_key":{ "default":"Ctrl+Shift+F", //默认win快捷键 "mac":"MacCtrl+Shift+F" }, "description":"打开popup.html" } } }
1
2
3
4
5
6
7
8
9
10
11
# 2、background scripts
使用流程:
1、需要在maniifest.json文件中声明,使用background api
{ "background":{ "scripts":["background.js"], "persistent":false } }
1
2
3
4
5
62、扩展程序一旦安装,会自动加载scripts标签定义的所有脚本,并查找需要监听的重要的事件,
例如:脚本文件中需要持久化变量信息,使用runtime.onInstalled的侦听事件,在onInstalled监听事件中,脚本使用chrome的存储API设置一个value,后续所有的扩展程序组件都可以访问或者修改这个value
chrome.runtime.onInstalled.addListener(() => { chrome.storage.sync.set({color:'red'},() =>{ console.log('color is red'); }); });
1
2
3
4
53、由于上述脚本使用了storage权限,在扩展插件开发中,涉及到API的使用,必须要提前声明,需要在permissions字段注册才能使用。
{ "permissions":["storage"], }
1
2
3代码示例:
//manifest.json { "name":"hello-word", "description":"你好,扩展插件", "version":"1.0", "manifest_version":2, "browser_action":{ "default_popup":"popup.html" }, "commands":{ "_execute_browser_action":{ "suggested_key":{ "default":"Ctrl+Shift+F", "mac":"MacCtrl+Shift+F" }, "description":"打开popup.html" } }, "permissions":["storage"], "background":{ "scripts":["background.js"], "persistent":false } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// background.js chrome.runtime.onInstalled.addListener(() => { chrome.storage.sync.set({color:'red'},() =>{ console.log('color is red'); }); });
1
2
3
4
5
6
# 3、UI界面
UI界面主要有两个,browser_action 和page_action,使用的时候两个选择一个,不可以同时使用,
主要区别:
browser_action 提供的功能面向全部网站,插件图标一直是激活的状态
page_action只针对对应网站提供的功能,插件需要配置激活规则,只有满足条件的网站才能使用插件,否则插件一直是灰色状态
# 3.1 、popup.html
在点击插件的时候会弹出弹框,弹框内容就是popup.html的内容,popup的内容在点击浏览器空白处会自动关闭
popup.html与普通html页面的区别就是不能使用内联script
# 3.2 popup.js
实战:使用脚本控制当前页面的背景色
popup.js
const changeColor = document.getElementById("changeColor"); changeColor.onclick = (element) =>{ chrome.storage.sync.get('color',(data) =>{ chrome.tabs.query({active:true, currentWindow: true},(tabs) =>{ chrome.tabs.executeScript( tabs[0].id, {code: `document.body.style.backgroundColor="${data.color}"`} ) }); }); };
1
2
3
4
5
6
7
8
9
10
11
12
# 4、扩展存储API
存储数据分为三类
1、浏览器本身的localStorage(HTML5特性)
2、chrome扩展自身的localStorage,需要注意content_script中的localStorage是存储在对应域名下的,别的域名不能访问,而background_script的localStorage是存储在chrome扩展下的,所有域名都可以访问,所以一般都会在background_script中存储公共信息,供所有页面使用。
3、chrome扩展的存储API(需要声明storage权限)
# 4.1、chrome扩展自身的localStorage
1、localStorage属于key/value存储类型,如果想要存储对象格式 ,就必须以json字符的格式来存储,后续再处理解析
2、API
//增加 localStorage.name = 'zhangsan'; || localStorage['name'] = 'zhangsan'; //修改 localStorage.name = 'lisi'; || localStorage['name'] = 'lisi'; //删除 localStorage.name = null; ||localStorage['name'] = null; //删除所有 localStorage.clear(); //查看 var name = localStorage.name; || var name = localStorage['name'];
1
2
3
4
5
6
7
8
9
10
# 4.2、chrome扩展存储API
1、可以看作是对localStorage的改进,可以将保存的数据写入本地磁盘,使用之前需要先声明storage权限
(数据存储目录:C:\Users\Administrator\AppData\Local\Google\Chrome\User Data\Default\Local Extension Settings\扩展id)
存储分为两种方式:sync和local,唯一的区别就是sync会开启当前用户的数据同步功能(不过由于墙的问题,大多数用户无法登录谷歌账户,也就不存在同步需求了)
2、API
//sync添加 chrome.storage.sync.set({key:value},()=>{ //添加成功 }); //local添加 chrome.storage.local.set({key:value},()=>{ //添加成功 }); //sync读取 chrome.storage.sync.get(['key'],(data)=>{ console.log(data.key); }); //local读取 chrome.storage.local.get(['key'],(data)=>{ console.log(data.key); }); //获取一个或多个数据所占用的总空间 getBytesInUse chrome.storage.sync.getBytesInUse(keys,(byts)=>{ console.log(byts); }) chrome.storage.local.getBytesInUse(keys,(byts)=>{ console.log(byts); }) 此处的 keys 只能为 null、字符串或包含多个字符串的数组 //删除数据 remove chrome.storage.sync.remove(keys,()=>{ //删除成功 }) chrome.storage.local.remove(keys,()=>{ //删除成功 }) keys 可以是字符串,也可以是包含多个字符串的数组 //删除所有数据 clear chrome.storage.sync.clear(()=>{ //删除成功 }) chrome.storage.local.clear(()=>{ //删除成功 }) //监听事件 onChange 当存储区的数据发生改变时,触发此方法 chrome.storage.onChaged.addListener((changes,storageArea)=>{ //callback() 会接收到两个参数,第一个为 changes,第二个是 StorageArea。changes 是词典对象,键为更改的属性名称,值包含两个属性,分别为 oldValue 和 newValue;StorageArea 为 local 或 sync。 });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 5、用户选项页面 (option)
# 6、书签管理
使用
chrome.bookmarks
能够创建、组织和操作书签,能够自定义操作书签的页面需要申请权限 [bookmarks]
注意:无法使用 chrome.bookmarks API 添加或删除根文件夹中的条目。无法重命名、移动或删除特殊的 “书签栏” 和 “其他” 文件夹。
# 1、获取所有书签信息
chrome.bookmarks.getTree(function callback)
chrome.bookmarks.getTree((res) => {
console.log(res);
})
2
3
返回数据示例:
通过这个方法能够拿到整个书签栏的树,而最外层就是根节点,根节点没有 title,根节点的两个子节点就是 书签栏和其他书签两个,id 分别是 1 和 2
# 2、获取某个节点的子树
chrome.bookmarks.getSubTree(string id, function callback)
chrome.bookmarks.getSubTree(tree[0].children[0].children[0].id, (res) => {
console.log(res);
})
`getSubTree(id) 需要传递id参数`
2
3
4
# 3、获取节点信息
chrome.bookmarks.get(string or array of string idOrIdList, function callback)
需要注意的是,无论是什么 get 方法,每次都是返回一个 Array 类型,即使请求的是节点,返回的也是 Array,并且不会返回子节点信息
get.onclick = (element) =>{
chrome.bookmarks.get('50', (res) => {
console.log(res);
})
}
2
3
4
5
# 4、获取所有的子节点
chrome.bookmarks.getChildren(string id, function callback)
getChildren.onclick = (element) =>{
chrome.bookmarks.getChildren('50', (res) => {
console.log(res);
})
}
2
3
4
5
# 5、获取最近的书签
chrome.bookmarks.getRecent(integer numberOfItems, function callback)
//返回最近创建的 3 个页签
getRecent.onclick = () => {
chrome.bookmarks.getRecent(3, (res) => {
console.log(res);
})
};
2
3
4
5
6
# 6、搜索书签
chrome.bookmarks.search(string or object query, function callback)
根据title和url属性进行不区分大小写的模糊匹配搜索页签节点数据
<div class="col-md-12">
<textarea id="title" cols="30" rows="1">github</textarea>
<button id="search" class="btn btn-primary">search</button>
</div>
search.onclick = (element) =>{
const title = document.getElementById("title").value;
chrome.bookmarks.search(title, (res) => {
console.log(res);
})
}
2
3
4
5
6
7
8
9
10
11
# 7、创建书签
chrome.bookmarks.create(object bookmark, function callback)
创建一个书签,在指定的
parentId
下创建书签或文件夹。如果 url 为NULL或没有该字段,会创建一个文件夹。如果
parentId
为1,则可以在根节点创建书签或文件夹
<div class="col-md-12">
创建书签
父书签名:<textarea id="pTitle" cols="30" rows="1">父书签名</textarea>
新书签名:<textarea id="newTitle" cols="30" rows="1">新书签名</textarea>
新书签地址:<textarea id="newUrl" cols="30" rows="1">新书签地址</textarea>
<button id="addBookmark" class="btn btn-primary">添加书签</button>
</div>
<div class="col-md-12">
根节点创建书签
新书签名:<textarea id="newTitle1" cols="30" rows="1">新书签名</textarea>
新书签地址:<textarea id="newUrl1" cols="30" rows="1">新书签地址</textarea>
<button id="addBookmark1" class="btn btn-primary">添加书签</button>
</div>
addBookmark.onclick = (element) =>{
const pTitle = document.getElementById("pTitle").value;
const newTitle = document.getElementById("newTitle").value;
const newUrl = document.getElementById("newUrl").value;
let obj
chrome.bookmarks.search(pTitle, (res) => {
obj = {
parentId:res[0]['id'],
title:newTitle,
url:newUrl
}
chrome.bookmarks.create(obj, (res) => {
console.log(res);
})
})
}
addBookmark1.onclick = (element) =>{
const newTitle1 = document.getElementById("newTitle1").value;
const newUrl1 = document.getElementById("newUrl1").value;
let obj
chrome.bookmarks.search(pTitle, (res) => {
obj = {
parentId:'1',
title:newTitle1,
url:newUrl1
}
chrome.bookmarks.create(obj, (res) => {
console.log(res);
})
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 8、移动书签
chrome.bookmarks.move(string id, object destination, function callback)
//把id为10的页签移动到id为1的节点下面
move.onclick = (element) =>{
const obj ={
parentId: '1'
}
chrome.bookmarks.move('10',obj, (res) => {
console.log(res);
})
}
2
3
4
5
6
7
8
9
# 9、更新书签
chrome.bookmarks.update(string id, object changes, function callback)
目前只支持更新title和url
//把书签id为8的title改为百度1
update.onclick = (element) =>{
const obj ={
title: '百度1'
}
chrome.bookmarks.update('8',obj, (res) => {
console.log(res);
})
}
2
3
4
5
6
7
8
9
10
# 10、删除书签或者空书签文件夹
chrome.bookmarks.remove(string id, function callback)
只能删除单个书签或者空文件夹,如果不是空文件夹则会报错
Can't remove non-empty folder (use recursive to force).
remove.onclick = (element) =>{
chrome.bookmarks.remove('272', (res) => {
console.log(res);
})
}
2
3
4
5
# 11、删除整个书签树
chrome.bookmarks.removeTree(string id, function callback)
可以删除当前书签和书签文件夹的子节点
removeTree.onclick = (element) =>{
chrome.bookmarks.removeTree('272', (res) => {
console.log(res);
})
}
2
3
4
5