[英]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.
我将在下面展示这些不同方法的示例。
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);
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 )注入的内容脚本:
chrome.storage.local
( MDN ) to pass the data (set prior to injecting your script).chrome.storage.local
( MDN )传递数据(在注入脚本之前设置)。document_start
, without the need for the content script to perform an asynchronous request.document_start
注入的manifest.json内容脚本,而无需内容脚本执行异步请求。chrome.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 )设置值。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.
它也没有使用动态值来构建执行代码的潜在安全问题,这是在下面的第二个选项中完成的。
chrome.storage.local.set()
( MDN ) .chrome.storage.local.set()
( MDN )存储数据。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"
});
});
chrome.storage.local.get()
( MDN ) .chrome.storage.local.get()
( MDN )读取数据。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。
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:在执行脚本之前,您可以注入一些代码,在内容脚本上下文中设置一个变量,然后您的主脚本可以使用该变量:
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.这个值很容易会破坏你正在注入的代码(即用户可能在他们输入的文本中使用
'
和/或"
)。如果你不以某种方式转义该值,则存在安全性可能导致执行任意代码的漏洞。
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,"\\'")
}
if (typeof newText === 'string') {
Array.from(document.querySelectorAll('textarea.comments')).forEach(el => {
el.value = newText;
});
}
See: Notes 1, 2, & 3.请参阅:注释 1、2 和 3。
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.
它有点复杂。
tabs.query()
( MDN ) .tabs.query()
( MDN )确定活动选项卡。tabs.executeScript()
( MDN )tabs.executeScript()
( MDN )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
});
});
});
chrome.runtime.onMessage.addListener()
( MDN ) .chrome.runtime.onMessage.addListener()
( MDN )添加一个监听器。runtime.onMessage
listenerruntime.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.