简体   繁体   English

从内容脚本访问后台脚本对象

[英]Accessing background script object from content script

How to access background script objects form a content script inside chrome extension? 如何访问后台脚本对象在chrome扩展内形成内容脚本?

In content script I have: 在内容脚本中,我有:

    // this will store settings
    var settings = {};

    // load settings from background
    chrome.extension.sendMessage({
        name: "get-settings"
    }, function(response) {
        debugger;
        settings = response.data.settings;
    }); 

Inside the background script I have: 在后台脚本中,我有:

    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();

Messaging works, i mean response is send but returned object is empty. 消息传递有效,我的意思是发送响应,但返回的对象为空。 Do you know how to solve that? 你知道怎么解决吗?

EDIT Based on your comments and answer will try to add different light to my question. 编辑根据您的评论和答案将尝试为我的问题添加不同的内容。

The actual problem is: How to access background "model" from content script . 实际的问题是: 如何从内容脚本访问后台“模型”

Lets assume that content script continuously responds to page DOM changes. 假设内容脚本持续响应页面DOM更改。 Any time changes are detected some processing is made inside content script . 每当检测到更改时,都会在内容脚本中进行一些处理。 But this processing is depended on extension setting. 但是此处理取决于扩展设置。 Those setting can be set via page action popup script which informs background model what those settings are. 可以通过页面操作弹出脚本来设置这些设置,该脚本会通知后台模型这些设置是什么。

So, any time page is processed with content script it should be aware of current settings stored inside background script . 因此,任何时候使用内容脚本处理页面时,都应该知道存储在后台脚本中当前设置。

As already described pulling settings from background is an asynchronous process, so i need a callback for further processing inside content script. 如前所述,从后台提取设置是一个异步过程,因此我需要回调以进一步在内容脚本中进行处理。 Further processing must wait for settings (so this should be handled synchronously?). 进一步的处理必须等待设置(因此应该同步处理吗?)。

It's hard for my to imagine what program flow should look like in this case. 我很难想象这种情况下的程序流程是什么样的。

  1. background loads (setting initialized) 后台加载(设置已初始化)
  2. page loads -> content script loads 页面加载->内容脚本加载
  3. content script requests settings -> further processing is done inside callback function. 内容脚本请求设置->在回调函数中进行进一步处理。
  4. user changes setting, background settings are changed 用户更改设置,背景设置更改
  5. page change is triggered and content script responds 页面更改被触发并且内容脚本响应
  6. content script requests settings -> further processing is done inside callback function - but it cannot be the same function like in pt. 内容脚本请求设置->在回调函数中进行进一步的处理-但不能与pt中的函数相同。 3 (content "model" does not have to be initialized)? 3(内容“模型”不必初始化)?
  1. sendMessage doesn't transfer the object itself, but only its JSON-ifiable representation, effectively objReceived = JSON.parse(JSON.stringify(objSent)) , so since your object's settingList is invisible outside function context it's lost during serialization. sendMessage不会传递对象本身,而只会传递其JSON可表示形式,即objReceived = JSON.parse(JSON.stringify(objSent)) ,因此,由于对象的settingList在函数上下文之外是不可见的,因此在序列化过程中会丢失。

    You can make it public by exposing a stringifiable property 您可以通过公开可字符串化的属性来将其公开

     this.settingList = { foo: 'bar' }; 

    that would be transferred to your content script successfully. 将会成功转移到您的内容脚本。

  2. Since messaging is asynchronous , to use the response in the content script you should do it inside the response callback: 由于消息传递是异步的 ,因此要在内容脚本中使用响应,应在响应回调中进行响应:

     // 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 } 
  3. To know if settings changed outside your content-script, in settings setter in background.js send messages to your tab's content-script: 要知道设置是否在内容脚本之外更改,请在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; }; 
  4. And in content-script listen and process this message: 然后在内容脚本中侦听并处理以下消息:

     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; } }); 

More details: https://developer.chrome.com/extensions/runtime#method-sendMessage . 更多详细信息: https : //developer.chrome.com/extensions/runtime#method-sendMessage

PS Use chrome.runtime.sendMessage instead of chrome.extension.sendMessage as the latter is deprecated in Chrome API and totally unsupported in WebExtensions API (Firefox/Edge). PS请使用chrome.runtime.sendMessage而不是chrome.extension.sendMessage因为Chrome API不推荐使用chrome.extension.sendMessage ,WebExtensions API(Firefox / Edge)完全不支持后者。

It would probably make more sense to have another instance of Settings in your content script. 在内容脚本中包含Settings另一个实例可能更有意义。

After all, chrome.storage API is available in content scripts. 毕竟,内容脚本中提供了chrome.storage API。

Of course, you need to watch for changes made in other parts of the extension - but you should be doing so anyway, since you're using chrome.storage.sync and its value can change independently by Chrome Sync. 当然,您需要注意在扩展程序其他部分所做的更改-但无论如何都应该这样做,因为您使用的是chrome.storage.sync ,Chrome Sync可以独立更改其值。

So, proposed solution: 因此,建议的解决方案:

  1. Add a listener to chrome.storage.onChanged and process changes to update your settingList as needed. 将监听器添加到chrome.storage.onChanged并处理更改以根据需要更新您的settingList
  2. Move the Storage logic to a separate JS "library", eg storage.js Storage逻辑移至单独的JS“库”,例如storage.js
  3. Load storage.js in your content script and use it normally. 在您的内容脚本中加载storage.js并正常使用。

You may also want to adjust your storage logic so that saved data is actually taken into account - right now it's always the default. 您可能还需要调整存储逻辑,以便实际考虑保存的数据-现在,它始终是默认值。 You can do something like this: 您可以执行以下操作:

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
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM