Remember state chrome extension

冷暖自知 提交于 2019-12-02 07:07:33

问题


I use a chrome extension to fire two content scripts to inject css. If the user opens the page the contentscript-on.js loads (defined in my manifest.json):

manifest.json

{
    "name": "tools",
    "version": "1.1",
    "description": "tools",
    "browser_action": {
        "default_icon": "icon-on.png",
        "default_title": "tools"
    },
    "manifest_version": 2,
    "content_scripts": [
        {
            "matches": [ "*://*/*" ],
            "include_globs": [ "*://app.example.*/*" ],
            "js": ["jquery-1.11.0.min.js", "contentscript-on.js"]
        }
    ],
    "background": {
        "scripts": ["background.js"],
        "persistent": true
    },
    "permissions": [
        "storage",
        "https://*.app.example.de/*", "tabs", "webNavigation"
    ]   
}

background.js

function getToggle(callback) { // expects function(value){...}
  chrome.storage.local.get('toggle', function(data){
    if(data.toggle === undefined) {
      callback(true); // default value
    } else {
      callback(data.toggle);
    }
  });
}

function setToggle(value, callback){ // expects function(){...}
  chrome.storage.local.set({toggle : value}, function(){
    if(chrome.runtime.lastError) {
      throw Error(chrome.runtime.lastError);
    } else {
      callback();
    }
  });
}

chrome.browserAction.onClicked.addListener( function(tab) {
  getToggle(function(toggle){
    toggle = !toggle;
    setToggle(toggle, function(){
      if(toggle){
    //change the icon after pushed the icon to On
    chrome.browserAction.setIcon({path: "icon-on.png", tabId:tab.id});
    //start the content script to hide dashboard
    chrome.tabs.executeScript({file:"contentscript-on.js"});
  }
  else{

    //change the icon after pushed the icon to Off
    chrome.browserAction.setIcon({path: "icon-off.png", tabId:tab.id});
    //start the content script to hide dashboard
    chrome.tabs.executeScript({file:"contentscript-off.js"});
  }
    });
  });
});  

contentscript-on.js

$(document).ready(function() {

    chrome.storage.local.get('toggle', function(data) {
        if (data.toggle === false) {
            return;
        } else {
            // do some css inject
        }
    });

});

contentscript-off.js

$(document).ready(function() {
  // set css to original 
});

Everything works fine, but how can I save the "state" of the icon? If the user close the browser and open it again, the last used contentscript should load.

Thank you very much for your help.


回答1:


You have two methods (at least), one is "old" and one is "new".

  1. Old: localStorage

    Your extension pages share a common localStorage object you can read/write, and it is persistent through browser restarts.

    Working with it is synchronous:

    var toggle;
    if(localStorage.toggle === undefined){
      localStorage.toggle = true;
    }
    toggle = localStorage.toggle;
    
    chrome.browserAction.onClicked.addListener( function(tab) {
      var toggle = !toggle;
      localStorage.toggle = toggle;
      /* The rest of your code; at this point toggle is saved */
    });
    

    It's simple to work with, but there are downsides: localStorage context is different for content scripts, so they need to communicate via Messaging to get the values from the background script; also, complications arise if the extension is used in Incognito mode.

  2. New: chrome.storage API

    To work with the new method, you need permission "storage" in the manifest (does not generate a warning).

    Also, unlike localStorage, working with it is asynchronous, i.e. you will need to use callbacks:

    function getToggle(callback) { // expects function(value){...}
      chrome.storage.local.get('toggle', function(data){
        if(data.toggle === undefined) {
          callback(true); // default value
        } else {
          callback(data.toggle);
        }
      });
    }
    
    function setToggle(value, callback){ // expects function(){...}
      chrome.storage.local.set({toggle : value}, function(){
        if(chrome.runtime.lastError) {
          throw Error(chrome.runtime.lastError);
        } else {
          callback();
        }
      });
    }
    
    chrome.browserAction.onClicked.addListener( function(tab) {
      getToggle(function(toggle){
        toggle = !toggle;
        setToggle(toggle, function(){
          /* The rest of your code; at this point toggle is saved */
        });
      });
    });
    

    Asynchronous code is a bit harder to work with, but you get some advantages. Namely, content scripts can use chrome.storage directly instead of communicating with the parent, you can watch for changes with onChanged, and you can use chrome.storage.sync instead of (or together with) chrome.storage.local to propagate changes to all browsers a user is logged into.

EDIT

I'm including a full solution, since the OP made a mistake of mixing per-tab state and global state.

contentscript.js

$(document).ready(function() {
  chrome.storage.local.get('toggle', function(data) {
    if (data.toggle === false) {
      return;
    } else {
      /* do some css inject */
    }
  });

  chrome.storage.onChanged.addListener(function(changes, areaName){
    if(areaName == "local" && changes.toggle) { 
      if(changes.toggle.newValue) {
        /* do some css inject */
      } else {
        /* set css to original */
      }
    }
  });
});

background.js:

    /* getToggle, setToggle as above */

    function setIcon(value){
      var path = (value)?"icon-on.png":"icon-off.png";
      chrome.browserAction.setIcon({path: path});
    }

    getToggle(setIcon); // Initial state

    chrome.browserAction.onClicked.addListener( function(tab) {
      getToggle(function(toggle){
        setToggle(!toggle, function(){
          setIcon(!toggle);
        });
      });
    });

This way, you only need one content script.



来源:https://stackoverflow.com/questions/23339944/remember-state-chrome-extension

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!