先上图
图中injected_script表示由content_script注入到页面的js,在这个js中通过dom操作的方式注入到原网页的js。这个js是完全和content_script,background,popup的js隔离,互相不能访问。
devtools-js一般都不会用到,只列出api。
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);
}
发送消息
// 获取当前选项卡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('我收到了你的消息!'); // 回调回去
});
发送消息
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_script和injected_script 之间共享的是dom元素和部分window对象,所有他们之间的通信由两种种方式:
第一种方法:
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,他们有
injected_script与content_script的通信方式是由其共享dom和部分window提供的api,他们有
微信群大佬都在等着你
微信扫描二维码加入微信群,交流学习,及时获取代码最新动态。