简体   繁体   English

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

[英]Pass a parameter to a content script injected using chrome.tabs.executeScript()

How can I pass a parameter to the JavaScript in a content script file which is injected using:如何在使用以下方式注入的内容脚本文件中将参数传递给 JavaScript:

chrome.tabs.executeScript(tab.id, {file: "content.js"});

There's not such a thing as "pass a parameter to a file".没有“将参数传递给文件”之类的东西。

What you can do is to either insert a content script before executing the file, or sending a message after inserting the file.可以做的是在执行文件之前插入内容脚本,或者在插入文件发送消息。 I will show an example for these distinct methods below.我将在下面展示这些不同方法的示例。

Set parameters before execution of the JS file在执行JS文件之前设置参数

If you want to define some variables before inserting the file, just nest chrome.tabs.executeScript calls:如果要在插入文件之前定义一些变量,只需嵌套chrome.tabs.executeScript调用:

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

If your variable is not as simple, then I recommend to use JSON.stringify to turn an object in a string:如果您的变量不是那么简单,那么我建议使用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'});
});

With the previous method, the variables can be used in content.js in the following way:使用前面的方法,可以通过以下方式在content.js中使用变量:

// content.js
alert('Example:' + config);

Set parameters after execution of the JS file JS文件执行后设置参数

The previous method can be used to set parameters after the JS file.可以使用前面的方法在 JS 文件后设置参数。 Instead of defining variables directly in the global scope, you can use the message passing API to pass parameters:您可以使用消息传递 API来传递参数,而不是直接在全局范围内定义变量:

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

In the content script ( content.js ), you can listen for these messages using the chrome.runtime.onMessage event, and handle the message:在内容脚本 ( content.js ) 中,您可以使用chrome.runtime.onMessage事件监听这些消息,并处理这些消息:

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

There are five general ways to pass data to a content script injected with tabs.executeScript() ( MDN ) :有五种通用方法可以将数据传递给使用tabs.executeScript() ( MDN )注入的内容脚本:

  • Set the data prior to injecting the script在注入脚本之前设置数据
    1. Use chrome.storage.local ( MDN ) to pass the data (set prior to injecting your script).使用chrome.storage.local ( MDN )传递数据(在注入脚本之前设置)。
    2. Inject code prior to your script which sets a variable with the data (see detailed discussion for possible security issue).在设置数据变量的脚本之前注入代码(有关可能的安全问题,请参阅详细讨论)。
    3. Set a cookie for the domain in which the content script is being injected.为要注入内容脚本的域设置一个 cookie。 This method can also be used to pass data to manifest.json content scripts which are injected at document_start , without the need for the content script to perform an asynchronous request.此方法还可用于将数据传递给在document_start注入的manifest.json内容脚本,而无需内容脚本执行异步请求。
  • Send/set the data after injecting the script注入脚本发送/设置数据
    1. Use message passing ( MDN ) to pass the data after your script is injected.注入脚本,使用消息传递( MDN )传递数据。
    2. Usechrome.storage.onChanged ( MDN ) in your content script to listen for the background script to set a value using chrome.storage.local.set() ( MDN ) .在内容脚本中使用chrome.storage.onChanged ( MDN )来侦听后台脚本以使用chrome.storage.local.set() ( MDN )设置值。

Use chrome.storage.local (set prior to executing your script)使用chrome.storage.local (在执行脚本之前设置)

Using this method maintains the execution paradigm you are using of injecting a script that performs a function and then exits.使用此方法可维护您正在使用的执行范例,即注入执行功能然后退出的脚本。 It also does not have the potential security issue of using a dynamic value to build executing code, which is done in the second option below.它也没有使用动态值来构建执行代码的潜在安全问题,这是在下面的第二个选项中完成的。

From your popup script:从您的弹出脚本中:

  1. Store the data using chrome.storage.local.set() ( MDN ) .使用chrome.storage.local.set() ( MDN )存储数据。
  2. In the callback for chrome.storage.local.set() , call tabs.executeScript() ( MDN ) .chrome.storage.local.set()的回调中,调用tabs.executeScript() ( MDN )
var updateTextTo = document.getElementById('comments').value;
chrome.storage.local.set({
    updateTextTo: updateTextTo
}, function () {
    chrome.tabs.executeScript({
        file: "content_script3.js"
    });
});

From your content script:从您的内容脚本:

  1. Read the data from chrome.storage.local.get() ( MDN ) .chrome.storage.local.get() ( MDN )读取数据。
  2. Make the changes to the DOM.对 DOM 进行更改。
  3. Invalidate the data in storage.local (eg remove the key with: chrome.storage.local.remove() ( MDN ) ).使storage.local中的数据无效(例如,使用chrome.storage.local.remove() ( MDN )删除密钥)。
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;
        });
    }
}

See: Notes 1 & 2.参见:注释 1 和 2。

Inject code prior to your script to set a variable在脚本之前注入代码以设置变量

Prior to executing your script, you can inject some code that sets a variable in the content script context which your primary script can then use:在执行脚本之前,您可以注入一些代码,在内容脚本上下文中设置一个变量,然后您的主脚本可以使用该变量:

Security issue:安全问题:

The following uses "'" + JSON.stringify().replace(/\\/g,'\\\\').replace(/'/g,"\\'") + "'" to encode the data into text which will be proper JSON when interpreted as code, prior to putting it in the code string.下面使用"'" + JSON.stringify().replace(/\\/g,'\\\\').replace(/'/g,"\\'") + "'"对数据进行编码在将其放入code字符串之前,将其解释为代码时将是正确的 JSON 文本。 The .replace() methods are needed to A) have the text correctly interpreted as a string when used as code, and B) quote any ' which exist in the data. .replace()方法需要 A) 在用作代码时将文本正确解释为字符串,并且 B) 引用数据中存在的任何' It then uses JSON.parse() to return the data to a string in your content script.然后它使用JSON.parse()将数据返回到内容脚本中的字符串。 While this encoding is not strictly required, it is a good idea as you don't know the content of the value which you are going to send to the content script.虽然这种编码不是严格要求的,但这是一个好主意,因为您不知道要发送到内容脚本的值的内容。 This value could easily be something that would corrupt the code you are injecting (ie The user may be using ' and/or " in the text they entered). If you do not, in some way, escape the value, there is a security hole which could result in arbitrary code being executed.这个值很容易会破坏你正在注入的代码(即用户可能在他们输入的文本中使用'和/或" )。如果你不以某种方式转义该值,则存在安全性可能导致执行任意代码的漏洞。

From your popup script:从您的弹出脚本中:

  1. Inject a simple piece of code that sets a variable to contain the data.注入一段简单的代码,设置一个变量来包含数据。
  2. In the callback for chrome.tabs.executeScript() ( MDN ) , call tabs.executeScript() to inject your script (Note: tabs.executeScript() will execute scripts in the order in which you call tabs.executeScript() , as long as they have the same value for runAt . Thus, waiting for the callback of the small code is not strictly required).chrome.tabs.executeScript() ( MDN )的回调中,调用tabs.executeScript()以注入您的脚本(注意: tabs.executeScript()将按照您调用tabs.executeScript()的顺序执行脚本,如只要它们的runAt的值相同。因此,等待小code的回调不是严格要求的)。
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,"\\'")
}

From your content script:从您的内容脚本:

  1. Make the changes to the DOM using the data stored in the variable使用存储在变量中的数据对 DOM 进行更改
if (typeof newText === 'string') {
    Array.from(document.querySelectorAll('textarea.comments')).forEach(el => {
        el.value = newText;
    });
}

See: Notes 1, 2, & 3.请参阅:注释 1、2 和 3。

Use message passing ( MDN ) (send data after content script is injected)使用消息传递MDN (在内容脚本注入发送数据)

This requires your content script code to install a listener for a message sent by the popup, or perhaps the background script (if the interaction with the UI causes the popup to close).这需要您的内容脚本代码为弹出窗口或后台脚本(如果与 UI 的交互导致弹出窗口关闭)发送的消息安装侦听器。 It is a bit more complex.它有点复杂。

From your popup script:从您的弹出脚本中:

  1. Determine the active tab usingtabs.query() ( MDN ) .使用tabs.query() ( MDN )确定活动选项卡。
  2. Call tabs.executeScript() ( MDN )调用tabs.executeScript() ( MDN )
  3. In the callback for tabs.executeScript() , usetabs.sendMessage() ( MDN ) (which requires knowing the tabId ), to send the data as a message.tabs.executeScript()的回调中,使用tabs.sendMessage() ( MDN ) (需要知道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
        });
    });
});

From your content script:从您的内容脚本:

  1. Add a listener usingchrome.runtime.onMessage.addListener() ( MDN ) .使用chrome.runtime.onMessage.addListener() ( MDN )添加一个监听器。
  2. Exit your primary code, leaving the listener active.退出您的主代码,让监听器保持活动状态。 You could return a success indicator, if you choose.如果您愿意,您可以返回一个成功指示器。
  3. Upon receiving a message with the data:收到带有数据的消息后:
    1. Make the changes to the DOM.对 DOM 进行更改。
    2. Remove your runtime.onMessage listener删除你的runtime.onMessage监听器

#3.2 is optional. #3.2 是可选的。 You could keep your code active waiting for another message, but that would change the paradigm you are using to one where you load your code and it stays resident waiting for messages to initiate actions.您可以让您的代码保持活动状态以等待另一条消息,但这会将您使用的范例更改为您加载代码并保持驻留等待消息启动操作的范例。

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
}

See: Notes 1 & 2.参见:注释 1 和 2。


Note 1: Using Array.from() is fine if you are not doing it many times and are using a browser version which has it (Chrome >= version 45, Firefox >= 32).注意 1:如果您没有多次使用Array.from()并且使用的是具有它的浏览器版本(Chrome >= 版本 45,Firefox >= 32),则使用 Array.from() 很好。 In Chrome and Firefox, Array.from() is slow compared to other methods of getting an array from a NodeList .在 Chrome 和 Firefox 中,与其他从 NodeList 获取数组的方法相比, Array.from()速度较慢 For a faster, more compatible conversion to an Array, you could use the asArray() code in this answer .为了更快、更兼容地转换为数组,您可以在此答案中使用asArray()代码。 The second version of asArray() provided in that answer is also more robust.该答案中提供的asArray()的第二个版本也更健壮。

Note 2: If you are willing to limit your code to Chrome version >= 51 or Firefox version >= 50 , Chrome has a forEach() method for NodeLists as of v51.注意 2:如果您愿意将代码限制为 Chrome 版本 >= 51 或 Firefox 版本 >= 50 ,Chrome 从 v51 开始为NodeLists提供了forEach()方法。 Thus, you don't need to convert to an array.因此,您不需要转换为数组。 Obviously, you don't need to convert to an Array if you use a different type of loop.显然,如果您使用不同类型的循环,则不需要转换为数组。

Note 3: While I have previously used this method (injecting a script with the variable value) in my own code, I was reminded that I should have included it here when reading this answer .注 3:虽然我之前在自己的代码中使用过这种方法(使用变量值注入脚本),但我被提醒在阅读此答案时应该将其包含在此处。

You can use the args property, see this documentation您可以使用args属性,请参阅此文档

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

Edit: My mistake - This only applies to injected functions, not files as the question specifies.编辑:我的错误 - 这仅适用于注入函数,而不是问题指定的文件。

@RobW's answer is the perfect answer for this. @RobW 的答案是完美的答案。 But for you to implement this you need to initiate global variables.但是要实现这一点,您需要启动全局变量。

I suggest an alternative for this, which is similar to @RobW's answer.我为此建议一个替代方案,类似于@RobW 的答案。 Instead of passing the variable to the file, you load a function from the content.js file and then initiate the function in your current context using the code: and pass variables from current context.您无需将变量传递给文件,而是从content.js文件加载 function,然后使用code:并从当前上下文传递变量。

var argString = "abc";
var argInt = 123;

chrome.tabs.executeScript(tabId, { file: "/content.js" }).then(() => {
    chrome.tabs.executeScript(tabId, {
        allFrames: false,
        code: "myFunction('" + argString + "', " + argInt + "); ",
    });
});

This is inspired from @wOxxOm's answer here .这是来自@wOxxOm 的答案here This method is really going to be helpful to write a common source code for Manifest v2 & v3这种方法对于编写 Manifest v2 & v3 的通用源代码真的很有帮助

暂无
暂无

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

相关问题 在chrome.tabs.executeScript中的javascript函数中传递参数 - Pass parameter in javascript function inside chrome.tabs.executeScript chrome.tabs.executeScript():如何获取内容脚本的结果? - chrome.tabs.executeScript(): How to get result of content script? 使用chrome.tabs.executeScript从脚本获取变量 - Get variable from a script using chrome.tabs.executeScript Google Chrome 扩展:通过 chrome.tabs.executeScript 将来自注入脚本的变量暴露给以相同方式注入的另一个脚本 - Google Chrome Extension: Expose variable from injected script via chrome.tabs.executeScript to another script injected the same way chrome.tabs.executeScript:如何从后台脚本中的内容脚本访问变量? - chrome.tabs.executeScript: How to get access to variable from content script in background script? chrome.tabs.executeScript-成功吗? - chrome.tabs.executeScript - succeeded? 如何将通过脚本通过chrome.tabs.executeScript()注入网页的脚本中的数组收集发送到另一个JS文件 - How to send array collect in a script that is programmatically injected into a web page via chrome.tabs.executeScript() to another JS file chrome.tabs.executeScript没有从内容页面返回结果 - chrome.tabs.executeScript is not returning results from content page 使用 chrome.tabs.executeScript(...) 时避免多次动态注入相同的脚本 - Avoid dynamically injecting the same script multiple times when using chrome.tabs.executeScript(...) 标签页更改URL或重新加载时使用chrome.tabs.executeScript - Using chrome.tabs.executeScript when the tab changes URL or reloads
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM