先上图
图中injected_script表示由content_script注入到页面的js,在这个js中通过dom操作的方式注入到原网页的js。这个js是完全和content_script,background,popup的js隔离,互相不能访问。
devtools-js一般都不会用到,只列出api。
popup和background
popup可以直接调用background中的JS方法,也可以直接访问background的DOM:
// background.js
function test()
{
alert('我是background!');
}
// popup.js
var bg = chrome.extension.getBackgroundPage(); // 核心api
bg.test(); // 访问bg的函数
alert(bg.document.body.innerHTML); // 访问bg的DOM
background访问popup,必须是在popup窗口打开的情况下,才能访问。
// background.js popup窗口必须打开
var views = chrome.extension.getViews({type:'popup'});
if(views.length > 0) {
console.log(views[0].location.href);
}
popup或者background向content_script发送消息
发送消息
// 获取当前选项卡ID
function getCurrentTabId(callback) {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
if (callback) callback(tabs.length ? tabs[0].id : null);
});
}
// 向标签中的content_script发送消息
function sendMessageToContentScript(message, callback) {
getCurrentTabId((tabId) => {
chrome.tabs.sendMessage(tabId, message, function (response) {
if (callback) callback(response);
});
});
}
content_script js接收消息
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse)
{
// console.log(sender.tab ?"from a content script:" + sender.tab.url :"from the extension");
if(request.cmd == 'test') alert(request.value);
sendResponse('我收到了你的消息!'); // 回调回去
});
content_script 发送消息
发送消息
chrome.runtime.sendMessage({ greeting: "你好" }, function (response) {
console.log(response.farewell);
});
background或者popup接收消息
// 监听来自content-script的消息
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse)
{
console.log('收到来自content-script的消息:');
console.log(request, sender, sendResponse);
sendResponse('我是后台,我已收到你的消息:' + JSON.stringify(request));
});
这里值得注意的是
- content_scripts向popup主动发消息的前提是popup必须打开!否则需要利用background作中转;
- 如果background和popup同时监听,那么它们都可以同时收到消息,但是只有一个可以sendResponse,一个先发送了,那么另外一个再发送就无效;
content_script和injected_script
content_script和injected_script 之间共享的是dom元素和部分window对象,所有他们之间的通信由两种种方式:
- 可以通过window.postMessage和window.addEventListener来实现二者消息通讯;
- 通过自定义DOM事件来实现;
第一种方法:
injected-script中
window.postMessage({"test": '你好!'}, '*');
content script中
window.addEventListener("message", function(e)
{
console.log(e.data);
}, false);
第二种方法dom事件有多种写法,这里介绍两种写法
1 通过模拟绑定div事件触发
injected-script中
var customEvent = document.createEvent('Event');
customEvent.initEvent('myCustomEvent', true, true);
function fireCustomEvent(data) {
hiddenDiv = document.getElementById('myCustomEventDiv');
hiddenDiv.innerText = data
hiddenDiv.dispatchEvent(customEvent);
}
fireCustomEvent('你好,我是普通JS!');
content script中
var hiddenDiv = document.getElementById('myCustomEventDiv');
if(!hiddenDiv) {
hiddenDiv = document.createElement('div');
hiddenDiv.style.display = 'none';
document.body.appendChild(hiddenDiv);
}
hiddenDiv.addEventListener('myCustomEvent', function() {
var eventData = document.getElementById('myCustomEventDiv').innerText;
console.log('收到自定义事件消息:' + eventData);
});
2 直接通过new CustomEvent()函数触发
content script中
var myEvent = new CustomEvent("test")
window.dispatchEvent(myEvent)
injected-script中监听
window.addEventListener("test", function (params) {
console.log(params);
})
当然new CustomEvent()也是可以传递参数的,具体用法参见MDN
长连接和短连接
Chrome插件中有2种通信方式,一个是短连接(chrome.tabs.sendMessage和chrome.runtime.sendMessage),一个是长连接(chrome.tabs.connect和chrome.runtime.connect)。上述的几种列出来的通信方式都应该归类于短连接。
请看长连接示例:
popup.js:
getCurrentTabId((tabId) => {
var port = chrome.tabs.connect(tabId, {name: 'test-connect'});
port.postMessage({question: '你是谁啊?'});
port.onMessage.addListener(function(msg) {
alert('收到消息:'+msg.answer);
if(msg.answer && msg.answer.startsWith('我是'))
{
port.postMessage({question: '哦,原来是你啊!'});
}
});
});
content-script.js:
// 监听长连接
chrome.runtime.onConnect.addListener(function(port) {
console.log(port);
if(port.name == 'test-connect') {
port.onMessage.addListener(function(msg) {
console.log('收到长连接消息:', msg);
if(msg.question == '你是谁啊?') port.postMessage({answer: '我是你爸!'});
});
}
});
总结:content_script,background,popup这三者之间的通信主要是使用chrome提供的API,他们有
- chrome.extension.getBackgroundPage()
- chrome.extension.getViews({type:‘popup’})
- chrome.tabs.sendMessage
- chrome.runtime.sendMessage
- chrome.runtime.onMessage.addListener
injected_script与content_script的通信方式是由其共享dom和部分window提供的api,他们有
- window.postMessage
- window.addEventListener
- document.createEvent
- window.dispatchEvent(myEvent)
微信群大佬都在等着你
微信扫描二维码加入微信群,交流学习,及时获取代码最新动态。