chrome扩展(插件)开发(四)content_script,background,popup,injected-script之间的消息通信通知以及数据传递

先上图
chrome扩展(插件)开发(四)content_script,background,popup,injected-script之间的消息通信通知以及数据传递_第1张图片
图中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_scriptbackgroundpopup这三者之间的通信主要是使用chrome提供的API,他们有

  • chrome.extension.getBackgroundPage()
  • chrome.extension.getViews({type:‘popup’})
  • chrome.tabs.sendMessage
  • chrome.runtime.sendMessage
  • chrome.runtime.onMessage.addListener

injected_scriptcontent_script的通信方式是由其共享dom和部分window提供的api,他们有

  • window.postMessage
  • window.addEventListener
  • document.createEvent
  • window.dispatchEvent(myEvent)

微信群大佬都在等着你

微信扫描二维码加入微信群,交流学习,及时获取代码最新动态。

你可能感兴趣的:(chrome插件开发,javascript,vue.js,html5,js,typescript)