在chrome
[1]插件开发中我们知道,background.js
是独立于浏览器的,在background.js
中主要负责popup
与content.js
的交互,在某些时候,也许你需要在一个插件的设置页与content
进行实时通信,此时你能想到什么样的方式吗?本文是在插件业务通信总结的一篇笔记,希望看完能在实际业务中带来思考和帮助
正文开始...
在插件通信中,我们先从background
、popup
、content
中来一起重温那些常用的通信交互
background.js
chrome.runtime.onMessage.addListener
监听content.js
发送过来的消息
// background.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
const { type } = request;
console.log(request)
if (type === "open_set_page") {
// 打开设置页
chrome.runtime.openOptionsPage();
}
})
content.js
在content.js
中,使用chrome.runtime.sendMessage(params)
,当我们在content.js
点击设置按钮时,此时就会打开设置页,此时会触发backrgound.js
// content.js
const setBtnDom = document.getElementById("set");
setBtnDom.onclick = function () {
// 向background.js传入消息
chrome.runtime.sendMessage({
type: "open_set_page",
});
};
设置页与background.js
通信
我们在content.js
中打开了一个设置页,此时如果设置页向与content
进行通信,那么该怎么办呢?
我们尝试在设置页
向background.js
中发送消息
document.getElementById("light").onclick = function () {
console.log("light");
// changeTheme,向background发送消息
chrome.runtime.sendMessage({ type: "changeTheme", theme: "light" });
};
我们会发现backrgound.js
中接收到了来自set
页面的信息
// background.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
const { type } = request;
// 打开设置页面
if (type == "open_set_page") {
chrome.runtime.openOptionsPage();
}
if (type === "changeTheme") {
console.log(request, "=request");
}
});
在一个插件的内部页面与content实时通信
比如现在有个场景,我在设置页需要设置content
页面的主题,而且需要实时修改,那么怎么办呢?
主要利用chrome.tabs.query
与chrome.tabs.sendMessage
这两个api实现
// set.js
function sendMessageToActiveTab(message) {
// 获取当前活动标签
chrome.tabs.query({}, function (tabs) {
tabs
.filter((v) => v.active)
.forEach((v) => {
chrome.tabs.sendMessage(v.id, message);
});
});
}
let flag = true;
document.getElementById("dark").onclick = function () {
flag = !flag;
sendMessageToActiveTab({ action: "buttonClicked", theme: flag ? "dark" : "light" });
};
在content.js
中我们监听set.js
发送过来的消息
const textDom = document.getElementById("text");
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
console.log(sender.id, chrome.runtime.id);
const {theme} = request;
textDom.style.color = theme === 'dark' ? "black": "red"
});
此时你会发现当你在设置点击按钮操作时,当前激活的tab
就会实时触发
但是有一个场景,就是我想修改所有的content
的状态,那该怎么办呢?
其实我们只需要修改一行代码即可
function sendMessageToActiveTab(message) {
// 向所有的tabde
chrome.tabs.query({}, function (tabs) {
tabs
.forEach((v) => {
chrome.tabs.sendMessage(v.id, message);
});
});
}
缓存
当你在设置页修改状态时,content
确实是可以实时变化了,但是,当你刷新,当前的状态的就会改变,所以你需要如何保持当前状态,那么你需要用到插件的缓存功能
在使用缓存功能之前,你需要在permission
中添加storage
{
"permissions": ["storage"]
}
在插件的设置页面
// set.js
let flag = true;
document.getElementById("dark").onclick = function () {
flag = !flag;
// port.postMessage({ type: "changeTheme", theme: "dark" });
const theme = flag ? "dark" : "light";
sendMessageToActiveTab({
action: "buttonClicked",
theme,
});
chrome.storage.local.set({ theme });
};
在content.js
中
// content.js
chrome.storage.local.get("theme", function (result) {
console.log(result, "result");
const { theme = "" } = result || { theme: "" };
if (theme === "dark") {
textDom.style.color = "black";
} else {
textDom.style.color = "red";
}
});
当你在chrome
设置页设置缓存时,你在content
重新刷新,那么就可以正常的获取缓存了。
总结
- 了解
content.js
与background.js
的通信,或者是popup
与content
的通信,借助chrome.runtime.sendMessage
实现 - 在插件的内部页面如何与其他页面通信,比如一个插件的设置页与
content.js
实时通信,我们是借助先查询所有的tabs,chrome.tabs.query({}, callback)
,然后再向所有的tabs发送消息chrome.tabs.sendMessage(id, data)
,最后在content.js
中chrome.runtime.onMessage
监听发送过来的消息 - 本文示例code example[2]
参考资料
[1]chrome: https://developer.chrome.com/docs/extensions/whatsnew/
[2]code example: https://github.com/maicFir/lessonNote/tree/master/chrome-plugin/06-demo