且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

关于注入脚本 + 本地存储的 Chrome 扩展

更新时间:2023-12-05 20:09:16

首先:您不需要注入脚本来访问页面的 DOM( 元素).DOM 已可用于内容脚本.

内容脚本不能直接访问扩展进程的localStorage,你需要在后台页面和内容脚本之间实现一个通信通道来实现这一点.幸运的是,Chrome 为此提供了一个简单的消息传递 API.

我建议使用 chrome.storageAPI 而不是 localStorage.chrome.storage 的优点是它可用于内容脚本,这允许您在没有背景页面的情况下读取/设置值.目前,您的代码看起来非常易于管理,因此从同步 localStorage 切换到异步 chrome.storage API 是可行的.

无论您如何选择,内容脚本的代码都必须异步读取/写入首选项:

//首选项名称示例,用于以下两个内容脚本示例var key = 'adurl';//使用消息传递的示例:chrome.extension.sendMessage({type:'getPref',key:key}, function(result) {//对结果做一些事情});//使用 chrome.storage 的示例:chrome.storage.local.get(key, function(items) {var 结果 = 项目 [key];//对结果做一些事情});

如您所见,两者之间几乎没有任何区别.但是,要让第一个工作,还必须在后台页面中添加更多逻辑:

//后台页面chrome.extension.onMessage.addListener(function(message, sender, sendResponse) {if (message.type === 'getPref') {var 结果 = localStorage.getItem(message.key);发送响应(结果);}});

另一方面,如果你想切换到 chrome.storage,你的选项页面中的逻辑必须稍微重写,因为当前的代码(使用 localStorage>) 是同步的,而 chrome.storage 是异步的:

//选项页面函数加载选项(){chrome.storage.local.get('repl_adurl', function(items) {var repl_adurl = items.repl_adurl;default_img.src = repl_adurl;tf_default_ad.value = repl_adurl;});}函数 save_options() {var tf_ad = document.getElementById('tf_default_ad');chrome.storage.local.set({repl_adurl: tf_ad.value});}

文档

I am puzzling my way through my first 'putting it all together' Chrome extension, I'll describe what I am trying to do and then how I have been going about it with some script excerpts:

  1. I have an options.html page and an options.js script that lets the user set a url in a textfield -- this gets stored using localStorage.

function load_options() {
   var repl_adurl = localStorage["repl_adurl"];
   default_img.src = repl_adurl;
   tf_default_ad.value = repl_adurl;
}

function save_options() {
   var tf_ad = document.getElementById("tf_default_ad");
   localStorage["repl_adurl"] = tf_ad.value;
}

document.addEventListener('DOMContentLoaded', function () {
   document.querySelector('button').addEventListener('click', save_options);
});

document.addEventListener('DOMContentLoaded', load_options );

  1. My contentscript injects a script 'myscript' into the page ( so it can have access to the img elements from the page's html )

var s = document.createElement('script');
s.src = chrome.extension.getURL("myscript.js");
console.log( s.src );
(document.head||document.documentElement).appendChild(s);
s.parentNode.removeChild(s);

  1. myscript.js is supposed to somehow grab the local storage data and that determines how the image elements are manipulated.

I don't have any trouble grabbing the images from the html source, but I cannot seem to access the localStorage data. I realize it must have to do with the two scripts having different environments but I am unsure of how to overcome this issue -- as far as I know I need to have myscript.js injected from contentscript.js because contentscript.js doesn't have access to the html source.

Hopefully somebody here can suggest something I am missing.

Thank you, I appreciate any help you can offer!

-Andy

First of all: You do not need an injected script to access the page's DOM (<img> elements). The DOM is already available to the content script.

Content scripts cannot directly access the localStorage of the extension's process, you need to implement a communication channel between the background page and the content script in order to achieve this. Fortunately, Chrome offers a simple message passing API for this purpose.

I suggest to use the chrome.storage API instead of localStorage. The advantage of chrome.storage is that it's available to content scripts, which allows you to read/set values without a background page. Currently, your code looks quite manageable, so switching from the synchronous localStorage to the asynchronous chrome.storage API is doable.

Regardless of your choice, the content script's code has to read/write the preferences asynchronously:

// Example of preference name, used in the following two content script examples
var key = 'adurl';

// Example using message passing:
chrome.extension.sendMessage({type:'getPref',key:key}, function(result) {
    // Do something with result
});
// Example using chrome.storage:
chrome.storage.local.get(key, function(items) {
    var result = items[key];
    // Do something with result
});

As you can see, there's hardly any difference between the two. However, to get the first to work, you also have to add more logic to the background page:

// Background page
chrome.extension.onMessage.addListener(function(message, sender, sendResponse) {
    if (message.type === 'getPref') {
        var result = localStorage.getItem(message.key);
        sendResponse(result);
    }
});

On the other hand, if you want to switch to chrome.storage, the logic in your options page has to be slightly rewritten, because the current code (using localStorage) is synchronous, while chrome.storage is asynchronous:

// Options page
function load_options() {
   chrome.storage.local.get('repl_adurl', function(items) {
       var repl_adurl = items.repl_adurl;
       default_img.src = repl_adurl;
       tf_default_ad.value = repl_adurl;
   });
}
function save_options() {
   var tf_ad = document.getElementById('tf_default_ad');
   chrome.storage.local.set({
       repl_adurl: tf_ad.value
   });
}

Documentation