背景
最近在工作中,有一个谷歌插件优化的一些需求,对于只知道用从来不知道写的我,看到一些谷歌插件api当时是一脸懵。因为自己也没有VPN,无奈,只得查现有的一些文档,来一步步探索。通过此次对谷歌插件也有了一个更深入的了解,也算是个不错的体验。并且不得不说,谷歌插件开发这玩应还蛮有意思的。
文件说明
popup
简单来说,这个就是当你点击谷歌插件,弹出的弹窗界面。拿CSDN插件来说,点击之后
这里有对应的popup.html以及对应的popup.js。也可以有对应的popup.css文件,但是我直接写在html中了。
background
这个就是后台一直运行的一个文件,也有对应的background.html以及对应的background.js
index
这个名字当时是随意的,并不一定要叫index,这个可以理解为你往你当前需要操作的页面中注入的js文件。通过这个文件,你可以拿到web中所有的dom等等信息。
manifest.json
这个就是谷歌插件的配置文件了,它有一些属性值。可以去根据自己需要的场景去配置这些信息。里面可能比较重要的就是content_scripts。
content_scripts
好人做到底,为了避免大家浏览到我这里还需要再额外浏览别的博客才能知道这些配置信息,我就把这里的我了解到的配置信息都例举出来,供大家参考。
名称 | 类型 | 必选/可选 | 说明 |
---|---|---|---|
matches | string数组 | 必选 | content script注入的页面 |
exclude_matches | string数组 | 可选 | content script不注入的页面 |
include_globs | string数组 | 必选 | 对于matches匹配的web页面,进一步限定URL |
exclude_globs | string数组 | 必选 | 对于matches匹配的web页面,进一步排查URL |
match_about_blank | string数组 | 必选 | 是否注入content script到about:blank和about:srcdoc页面,默认false |
css | string数组 | 必选 | 注入到匹配的web页面中的CSS文件,顺序相关 |
js | string数组 | 必选 | 注入到匹配的web页面中的JS文件,顺序相关 |
run_at | string数组 | 必选 | 控制JS文件注入的时机,如“document_start”,“document_end”,“document_idle”,默认"document_idle" document_start 表示在CSS文件之后,DOM构建或其他脚本运行之前,注入JS文件document_end 表示在DOM构建结束之后,图片或框架加载之前,注入JS文件document_idle 表示在document_end与触发window.onload事件之间的某个事件,注入JS文件,具体事件可以根据页面的内容和加载的进度优化 |
all_frames | boolean | 可选 | 控制JS文件是否在匹配的Web页面中的所有框架中运行,默认false表示只在顶层框架中运行 |
需要注意的一些地方
- 如果你需要页面上的值,但是你想要应用的网页是否是里面有iframe,如果有的话,你可能需要all_frames为true。这样就可以拿到了呢。
- 拿到了之后,你又会发现另一个问题,就是注入web页面的文件执行了两次。what?因为会先查顶层,再查web页面的iframe,所以执行两次,没毛病啊!
- 那应该如何解决这个问题呢?如果顶层中没有你要用到的信息,就直接window.self !== window.top规避掉。如果顶层中有你需要的信息,可以存到缓存当中,然后打断后续流程,下一次从缓存中去取这个值。
通信
开发完这个谷歌插件,我是发现了,啥东西都离不了通信啊。比如当点击了插件弹窗页面的按钮,想要当前web页面出现一些交互的时候,此时应该如何做到呢??
长连接
比如点击弹窗页面的按钮之后,需要拿到当前页面数据,然后在当前页面做出具体提示的时候。就可以考虑这种连接方式。
popup/background ----> index
popup/background.js
// 获取tabId
function getCurrentTabId(callback) {
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
if (callback) callback(tabs.length ? tabs[0].id : null);
});
}
// 建立长连接
function callbackInfo(tabId) {
var port = chrome.tabs.connect(tabId, { name: 'connect' });
port.postMessage({ status: 'ok' });
}
// 点击触发
$(".btn").click(function () {
getCurrentTabId(callbackInfo);
})
index.js
// 规避顶层查找
if (window.self !== window.top) {
// 监听连接
chrome.runtime.onConnect.addListener(function(port) {
targetPort = port;
console.log(port,'port');
if(targetPort.name == 'connect') {
targetPort.onMessage.addListener(function(msg) {
console.log('收到长连接消息:', msg);
if(msg.status == 'ok') {
handleDebounce()
}
});
}
});
}
短连接
popup <----> background
popup可以直接调用background中的JS方法,也可以直接访问background的DOM
// background.js
function test()
{
alert('我是background!');
}
// popup.js
var bg = chrome.extension.getBackgroundPage();
bg.test(); // 访问bg的函数
alert(bg.document.body.innerHTML); // 访问bg的DOM
background访问popup的前提是,popup已经打开了
var views = chrome.extension.getViews({type:'popup'});
if (views.length > 0) {
console.log(views[0].location.href);
}
嗯嗯嗯嗯,目前接触到的就是这些了,后续有新的内容还会补充上来~