如何从chrome扩展程序中的内容脚本访问后台脚本对象?
在内容脚本中我有:
// this will store settings
var settings = {};
// load settings from background
chrome.extension.sendMessage({
name: "get-settings"
}, function(response) {
debugger;
settings = response.data.settings;
});
在后台脚本中我有:
var Settings = function() {
var me = this;
// internal, default
var settingList = {
serverUrl : "http://automatyka-pl.p4",
isRecordingEnabled : true,
isScanEnabled : true
};
this.get = function( key ) {
return settingList[key];
};
this.set = function( key , value ) {
if (settingList[key] != value) {
var setting = {};
setting[key] = value;
chrome.storage.sync.set(setting, function() {
settingList[key] = value;
});
}
return true;
};
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
if (request.name == 'get-settings') {
sendResponse({
data : {
settings : settings
}
});
return true;
}
});
var settings = new Settings();
消息传递有效,我的意思是响应是发送但返回的对象是空的。你知道如何解决这个问题吗?
修改 根据您的评论和答案,我会尝试为我的问题添加不同的亮点。
实际问题是: 如何访问背景"模型"来自内容脚本。
让我们假设内容脚本持续响应页面DOM更改。任何时候检测到更改,都会在内容脚本中进行一些处理。但此处理取决于扩展设置。这些设置可以通过页面动作弹出脚本设置,它会通知背景模型这些设置是什么。
因此,任何时候使用内容脚本处理页面时,都应该知道存储在后台脚本中的当前设置。
如前所述,从后台提取设置是一个异步过程,所以我需要一个回调来进一步处理内容脚本。进一步处理必须等待设置(所以这应该同步处理?)。
在这种情况下,我很难想象程序流应该是什么样子。
答案 0 :(得分:2)
sendMessage不传输对象本身,但只传输其JSON-ifiable表示,
有效objReceived = JSON.parse(JSON.stringify(objSent))
,因为您的对象settingList
在函数上下文之外是不可见的,所以它在序列化过程中丢失了。
您可以通过展示可字符串属性
来使其公开this.settingList = { foo: 'bar' };
将成功传输到您的内容脚本。
由于消息传递是asynchronous,要在内容脚本中使用响应,您应该在响应回调中执行此操作:
// this will store the settings
var settings = {};
// load settings from background
chrome.runtime.sendMessage({
name: "get-settings"
}, function(response) {
settings = response.data.settings;
onSettingsReady();
});
function onSettingsReady() {
// put your logic here, settings are set at this point
}
要了解设置是否在内容脚本之外更改,请在background.js的设置设置器中将消息发送到标签的内容脚本:
this.set = function( key , value ) {
...
// notify active tab if settings changed
chrome.tabs.query({"windowType":"normal"}, function(tabs){
for( id in tabs ){
if("id" in tabs[id]){
chrome.tabs.sendMessage(tabs[id].id,{"action":"update-settings","settings":settings});
}
}
});
return true;
};
在内容脚本中侦听并处理此消息:
chrome.runtime.onMessage.addListener(function(msg){
if("action" in msg && msg.action == 'update-settings'){
// You are setting global settings variable, so on it will be visible in another functions too
settings = msg.settings;
}
});
更多详情:https://developer.chrome.com/extensions/runtime#method-sendMessage。
P.S。使用chrome.runtime.sendMessage
代替chrome.extension.sendMessage
,因为后者在Chrome API中已弃用,而且在WebExtensions API(Firefox / Edge)中完全不受支持。
答案 1 :(得分:0)
在内容脚本中添加Settings
的另一个实例可能更有意义。
毕竟,内容脚本中提供了chrome.storage
API。
当然,您需要关注在扩展程序的其他部分中所做的更改 - 但是您应该这样做,因为您使用的是chrome.storage.sync
,并且其值可以通过Chrome同步更改。
所以,建议的解决方案:
chrome.storage.onChanged
添加一个监听器并处理更改以根据需要更新您的settingList
。Storage
逻辑移动到单独的JS“库”,例如storage.js
storage.js
并正常使用。您可能还想调整存储逻辑,以便将实际的已保存数据考虑在内 - 现在它始终是默认值。你可以这样做:
var defaultSettingList = {
serverUrl : "http://automatyka-pl.p4",
isRecordingEnabled : true,
isScanEnabled : true
};
var settingList = Object.assign({}, defaultSettingList);
chrome.storage.sync.get(defaultSettingList, function(data) {
settingList = Object.assign(settingList, data);
// At this point you probably should call the "ready" callback - initial
// load has to be async, no way around it
});