chrome的其他特性

893 阅读4分钟

动态注入或执行JS

虽然在backgroundpopup中无法直接访问页面DOM,但是可以通过chrome.tabs.executeScript来执行脚本,从而实现访问web页面的DOM(注意,这种方式也不能直接访问页面JS)。

示例manifest.json配置:

 复制代码
{ "name": "动态JS注入演示", ... "permissions": [ "tabs", "http://*/*", "https://*/*" ], ...}

JS:

// 动态执行JS代码chrome.tabs.executeScript(tabId, {code: 'document.body.style.backgroundColor="red"'});// 动态执行JS文件chrome.tabs.executeScript(tabId, {file: 'some-script.js'});

动态注入CSS

示例manifest.json配置:

{ "name": "动态CSS注入演示", ... "permissions": [ "tabs", "http://*/*", "https://*/*" ], ...}

JS代码:

 复制代码
// 动态执行CSS代码,TODO,这里有待验证chrome.tabs.insertCSS(tabId, {code: 'xxx'});// 动态执行CSS文件chrome.tabs.insertCSS(tabId, {file: 'some-style.css'});

获取当前窗口ID

`chrome.windows.getCurrent(function(currentWindow)`
`{`
`console.log('当前窗口ID:' + currentWindow.id);`
`});`

## 获取当前标签页ID
一般有2种方法:

// 获取当前选项卡IDfunction getCurrentTabId(callback){ chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { if(callback) callback(tabs.length ? tabs[0].id: null); });}


获取当前选项卡id的另一种方法,大部分时候都类似,只有少部分时候会不一样(例如当窗口最小化时)

// 获取当前选项卡IDfunction getCurrentTabId2(){ chrome.windows.getCurrent(function(currentWindow) { chrome.tabs.query({active: true, windowId: currentWindow.id}, function(tabs) { if(callback) callback(tabs.length ? tabs[0].id: null); }); });}


## 本地存储
本地存储建议用`chrome.storage`而不是普通的`localStorage`,区别有好几点,个人认为最重要的2点区别是:

-   `chrome.storage`是针对插件全局的,即使你在`background`中保存的数据,在`content-script`也能获取到;
-   `chrome.storage.sync`可以跟随当前登录用户自动同步,这台电脑修改的设置会自动同步到其它电脑,很方便,如果没有登录或者未联网则先保存到本地,等登录了再同步至网络;

需要声明`storage`权限,有`chrome.storage.sync``chrome.storage.local`2种方式可供选择,使用示例如下:

// 读取数据,第一个参数是指定要读取的key以及设置默认值chrome.storage.sync.get({color: 'red', age: 18}, function(items) { console.log(items.color, items.age);});// 保存数据chrome.storage.sync.set({color: 'blue'}, function() { console.log('保存成功!');});


## webRequest

通过[webRequest](https://developer.chrome.com/extensions/webRequest)系列API可以对HTTP请求进行任性地修改、定制,下面是`webRequest`的几个生命周期:

![webRequest - 图1](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/432fc16afdf44a0c891e32f7c0ec54ae~tplv-k3u1fbpfcp-zoom-1.image)

这里通过`beforeRequest`来简单演示一下它的冰山一角:

//manifest.json{ // 权限申请 "permissions": [ "webRequest", // web请求 "webRequestBlocking", // 阻塞式web请求 "storage", // 插件本地存储 "http:///", // 可以通过executeScript或者insertCSS访问的网站 "https:///" // 可以通过executeScript或者insertCSS访问的网站 ],}// background.js// 是否显示图片var showImage;chrome.storage.sync.get({showImage: true}, function(items) { showImage = items.showImage;});// web请求监听,最后一个参数表示阻塞式,需单独声明权限:webRequestBlockingchrome.webRequest.onBeforeRequest.addListener(details => { // cancel 表示取消本次请求 if(!showImage && details.type == 'image') return {cancel: true}; // 简单的音视频检测 // 大部分网站视频的type并不是media,且视频做了防下载处理,所以这里仅仅是为了演示效果,无实际意义 if(details.type == 'media') { chrome.notifications.create(null, { type: 'basic', iconUrl: 'img/icon.png', title: '检测到音视频', message: '音视频地址:' + details.url, }); }}, {urls: ["<all_urls>"]}, ["blocking"]);


几个可能经常用到的事件使用示例:

// 每次请求前触发,可以拿到 requestBody 数据,同时可以对本次请求作出干预修改chrome.webRequest.onBeforeRequest.addListener(details => { console.log('onBeforeRequest', details);}, {urls: ['<all_urls>']}, ['blocking', 'extraHeaders', 'requestBody']);// 发送header之前触发,可以拿到请求headers,也可以添加、修改、删除headers// 但使用有一定限制,一些特殊头部可能拿不到或者存在特殊情况,详见官网文档chrome.webRequest.onBeforeSendHeaders.addListener(details => { console.log('onBeforeSendHeaders', details);}, {urls: ['<all_urls>']}, ['blocking', 'extraHeaders', 'requestHeaders']);// 开始响应触发,可以拿到服务端返回的headerschrome.webRequest.onResponseStarted.addListener(details => { console.log('onResponseStarted', details);}, {urls: ['<all_urls>']}, ['extraHeaders', 'responseHeaders']);// 请求完成触发,能拿到的数据和onResponseStarted一样,注意无法拿到responseBodychrome.webRequest.onCompleted.addListener(details => { console.log('onCompleted', details);}, {urls: ['<all_urls>']}, ['extraHeaders', 'responseHeaders']);


上面示例中提到,使用`webRequest`API是无法拿到`responseBody`的,想要拿到的话只能采取一些变通方法,例如:

1.  重写`XmlHttpRequest``fetch`,增加自定义拦截事件,缺点是实现方式可能有点脏,重写不好的话可能影响正常页面;
1.  `devtools``chrome.devtools.network.onRequestFinished`API可以拿到返回的body,缺点是必须打开开发者面板;
1.  使用`chrome.debugger.sendCommand`发送`Network.getResponseBody`命令来获取body内容,缺点也很明显,会有一个恼人的提示:

![webRequest - 图2](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/61b96b401c5a46a6812c413349d59245~tplv-k3u1fbpfcp-zoom-1.image)

上述几种方法的实现方式这个链接基本上都有,可以参考下:<https://stackoverflow.com/questions/18534771/chrome-extension-how-to-get-http-response-body>

## 国际化
插件根目录新建一个名为`_locales`的文件夹,再在下面新建一些语言的文件夹,如`en``zh_CN``zh_TW`,然后再在每个文件夹放入一个`messages.json`,同时必须在清单文件中设置`default_locale``_locales\en\messages.json`内容:

{ "pluginDesc": {"message": "A simple chrome extension demo"}, "helloWorld": {"message": "Hello World!"}}


`_locales\zh_CN\messages.json`内容:

{ "pluginDesc": {"message": "一个简单的Chrome插件demo"}, "helloWorld": {"message": "你好啊,世界!"}}

`manifest.json``CSS`文件中通过`__MSG_messagename__`引入,如:

{ "description": "MSG_pluginDesc", // 默认语言 "default_locale": "zh_CN",}


JS中则直接`chrome.i18n.getMessage("helloWorld")`。

测试时,通过给chrome建立一个不同的快捷方式`chrome.exe --lang=en`来切换语言,如:

![国际化 - 图1](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/652d0669fdef434cab22e6a9924d5c3b~tplv-k3u1fbpfcp-zoom-1.image)

英文效果:

![国际化 - 图2](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/65b5556c13b44920b28135b0575893b1~tplv-k3u1fbpfcp-zoom-1.image)

中文效果:

![国际化 - 图3](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a9cdb7526b63484aa21cf160eb8ec45e~tplv-k3u1fbpfcp-zoom-1.image)