将参数传递给使用chrome.tabs.executeScript()注入的内容脚本

use*_*732 46 javascript google-chrome-extension

如何将参数传递给内容脚本文件中的JavaScript,该文件使用以下方式注入:

chrome.tabs.executeScript(tab.id, {file: "content.js"});
Run Code Online (Sandbox Code Playgroud)

Rob*_*b W 94

没有"将参数传递给文件"这样的事情.

可以做的是执行文件之前插入内容脚本,或插入文件发送消息.我将在下面展示这些不同方法的示例.

在执行JS文件之前设置参数

如果要在插入文件之前定义一些变量,只需嵌套chrome.tabs.executeScript调用:

chrome.tabs.executeScript(tab.id, {
    code: 'var config = 1;'
}, function() {
    chrome.tabs.executeScript(tab.id, {file: 'content.js'});
});
Run Code Online (Sandbox Code Playgroud)

如果您的变量不那么简单,那么我建议使用JSON.stringify转换字符串中的对象:

var config = {somebigobject: 'complicated value'};
chrome.tabs.executeScript(tab.id, {
    code: 'var config = ' + JSON.stringify(config)
}, function() {
    chrome.tabs.executeScript(tab.id, {file: 'content.js'});
});
Run Code Online (Sandbox Code Playgroud)

使用前面的方法,可以通过content.js以下方式使用变量:

// content.js
alert('Example:' + config);
Run Code Online (Sandbox Code Playgroud)

执行JS文件后设置参数

以前的方法可用于在JS文件之后设置参数.您可以使用消息传递API来传递参数,而不是直接在全局范围内定义变量:

chrome.tabs.executeScript(tab.id, {file: 'content.js'}, function() {
    chrome.tabs.sendMessage(tab.id, 'whatever value; String, object, whatever');
});
Run Code Online (Sandbox Code Playgroud)

在内容脚本(content.js)中,您可以使用chrome.runtime.onMessage事件侦听这些消息,并处理消息:

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
    // Handle message.
    // In this example, message === 'whatever value; String, object, whatever'
});
Run Code Online (Sandbox Code Playgroud)

  • @ user1365732是的,因为你必须读取该对象的属性.在这个例子中,`config.somebigobject`.请注意,"somebigobject"可以是任何东西,我只想展示如何执行此操作,并通过选择不太可能的名称,如"somebigobject",我想传达的信息是,您可以在该对象上放置任何您想要的内容. (2认同)

Mak*_*yen 14

将数据传递给注入(MDN)的内容脚本有五种通用方法:tabs.executeScript()

  • 注入脚本 之前设置数据
    1. 使用(MDN)传递数据(在注入脚本之前设置).chrome.storage.local
    2. 在脚本之前注入代码,该代码使用数据设置变量(有关可能的安全问题,请参阅详细讨论).
    3. 为正在注入内容脚本的域设置cookie.此方法还可用于将数据传递到注入的manifest.json内容脚本document_start,而无需内容脚本执行异步请求.
  • 注入脚本 发送/设置数据
    1. 注入脚本后,使用消息传递(MDN)传递数据.
    2. 在内容脚本中使用(MDN)侦听后台脚本以使用(MDN)设置值.chrome.storage.onChangedchrome.storage.local.set()

使用chrome.storage.local(在执行脚本之前设置)

使用此方法可以维护您正在使用的执行范例,即注入执行函数的脚本然后退出.它也没有使用动态值来构建执行代码的潜在安全问题,这在下面的第二个选项中完成.

从弹出脚本:

  1. 使用(MDN)存储数据.chrome.storage.local.set()
  2. 在回调中chrome.storage.local.set(),调用(MDN).tabs.executeScript()
var updateTextTo = document.getElementById('comments').value;
chrome.storage.local.set({
    updateTextTo: updateTextTo
}, function () {
    chrome.tabs.executeScript({
        file: "content_script3.js"
    });
});
Run Code Online (Sandbox Code Playgroud)

从您的内容脚本:

  1. (MDN)读取数据.chrome.storage.local.get()
  2. 对DOM进行更改.
  3. 使数据无效storage.local(例如,使用:(MDN)删除密钥).chrome.storage.local.remove() 
chrome.storage.local.get('updateTextTo', function (items) {
    assignTextToTextareas(items.updateTextTo);
    chrome.storage.local.remove('updateTextTo');
});
function assignTextToTextareas(newText){
    if (typeof newText === 'string') {
        Array.from(document.querySelectorAll('textarea.comments')).forEach(el => {
            el.value = newText;
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

见:注1和2.

在脚本之前注入代码以设置变量

在执行脚本之前,您可以注入一些代码,这些代码在内容脚本上下文中设置一个变量,然后主脚本可以使用该代码:

安全问题:

以下用于"'" + JSON.stringify().replace(/\\/g,'\\\\').replace(/'/g,"\\'") + "'"将数据编码为文本,在将其解释为代码之前将其作为正确的JSON,然后将其放入code字符串中..replace()需要这些方法A)在用作代码时将文本正确解释为字符串,并且B)引用'数据中存在的任何文本.然后,它JSON.parse()用于将数据返回到内容脚本中的字符串.虽然此编码并非严格要求,但最好不要知道要发送到内容脚本的值的内容.这个值可能很容易破坏你注入的代码(即用户可能正在使用'和/或"在他们输入的文本中).如果不以某种方式逃避该值,则存在可能导致执行任意代码的安全漏洞.

从弹出脚本:

  1. 注入一段设置变量以包含数据的简单代码.
  2. (MDN)的回调中,调用注入脚本(注意:将按照您调用的顺序执行脚本,只要它们具有相同的值.因此,等待小的回调不是严格要求的).chrome.tabs.executeScript()tabs.executeScript()tabs.executeScript()tabs.executeScript()runAtcode
var updateTextTo = document.getElementById('comments').value;
chrome.tabs.executeScript({
    code: "var newText = JSON.parse('" + encodeToPassToContentScript(updateTextTo) + "');"
}, function () {
    chrome.tabs.executeScript({
        file: "content_script3.js"
    });
});

function encodeToPassToContentScript(obj){
    //Encodes into JSON and quotes \ characters so they will not break
    //  when re-interpreted as a string literal. Failing to do so could
    //  result in the injection of arbitrary code and/or JSON.parse() failing.
    return JSON.stringify(obj).replace(/\\/g,'\\\\').replace(/'/g,"\\'")
}
Run Code Online (Sandbox Code Playgroud)

从您的内容脚本:

  1. 使用存储在变量中的数据对DOM进行更改
if (typeof newText === 'string') {
    Array.from(document.querySelectorAll('textarea.comments')).forEach(el => {
        el.value = newText;
    });
}
Run Code Online (Sandbox Code Playgroud)

请参阅:注释1,2和3.

使用消息传递(MDN)(注入内容脚本发送数据)

这需要您的内容脚本代码为弹出窗口或后台脚本发送的消息安装监听器(如果与UI的交互导致弹出窗口关闭).它有点复杂.

从弹出脚本:

  1. 使用(MDN)确定活动选项卡.tabs.query()
  2. 致电(MDN)tabs.executeScript()
  3. 在回调中tabs.executeScript(),使用(MDN)(需要知道),将数据作为消息发送.tabs.sendMessage()tabId
var updateTextTo = document.getElementById('comments').value;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    chrome.tabs.executeScript(tabs[0].id, {
        file: "content_script3.js"
    }, function(){
        chrome.tabs.sendMessage(tabs[0].id,{
            updateTextTo: updateTextTo
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

从您的内容脚本:

  1. 使用(MDN)添加侦听器.chrome.runtime.onMessage.addListener()
  2. 退出主代码,使侦听器保持活动状态.如果您愿意,可以返回成功指标.
  3. 收到包含数据的消息后:
    1. 对DOM进行更改.
    2. 删除你的runtime.onMessage听众

#3.2是可选的.您可以使代码保持活动状态等待另一条消息,但这会将您正在使用的范例更改为加载代码的范例,并且它会驻留在等待消息启动操作的驻留位置.

chrome.runtime.onMessage.addListener(assignTextToTextareas);
function assignTextToTextareas(message){
    newText = message.updateTextTo;
    if (typeof newText === 'string') {
        Array.from(document.querySelectorAll('textarea.comments')).forEach(el => {
            el.value = newText;
        });
    }
    chrome.runtime.onMessage.removeListener(assignTextToTextareas);  //optional
}
Run Code Online (Sandbox Code Playgroud)

见:注1和2.


注意1:Array.from()如果您没有多次使用并使用具有它浏览器版本(Chrome> =版本45,Firefox> = 32),则使用正常.在Chrome和Firefox中,Array.from()与从NodeList获取数组的其他方法相比,速度较慢.要更快,更兼容地转换为数组,您可以使用此答案中asArray()代码.该答案中提供的第二个版本也更强大.asArray()

注意2:如果您愿意将代码限制为Chrome版本> = 51或Firefox版本> = 50,则Chrome有一个自v51 以来的NodeListsforEach()方法.因此,您不需要转换为数组.显然,如果使用不同类型的循环,则不需要转换为数组.

注3:虽然我以前在我自己的代码中使用过这种方法(用变量值注入一个脚本),但我还是提醒一下,在阅读这个答案时我应该把它包含在这里.


Tsa*_*nas 14

您可以使用该args属性,请参阅此文档

const color = '#00ff00';
function changeBackgroundColor(backgroundColor) {
  document.body.style.backgroundColor = backgroundColor;
}
chrome.scripting.executeScript(
    {
      target: {tabId},
      func: changeBackgroundColor,
      args: [color],
    },
    () => { ... });
Run Code Online (Sandbox Code Playgroud)

编辑:我的错误 - 这仅适用于注入的函数,而不适用于问题指定的文件。