有三种一般的方法可以实现这个:
- 使用
chrome.storage.local
(MDN) 传递数据(在注入脚本之前设置)。
- 在注入脚本之前插入代码,设置一个带有数据的变量(可能存在安全问题,请参见详细讨论)。
- 使用 message passing (MDN) 在注入脚本后传递数据。
使用 chrome.storage.local
(在执行脚本之前设置)
使用此方法可以保持您正在使用的注入执行范例,即注入执行函数然后退出。它也没有使用动态值构建执行代码的潜在安全问题,这是下面第二个选项中完成的。
从您的弹出式脚本开始:
- 使用
chrome.storage.local.set()
(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)读取数据
- 对DOM进行更改
- 使
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;
});
}
}
请参见:注释1和2。
在脚本之前注入代码以设置变量
在执行您的脚本之前,您可以注入一些代码来设置内容脚本上下文中的变量,然后您的主要脚本可以使用该变量:
安全问题:
以下使用
"'" + JSON.stringify().replace(/\\/g,'\\\\').replace(/'/g,"\\'") + "'"
将数据编码为文本,当作代码解释之前,放入
code
字符串中。
.replace()
方法需要用于A)在使用代码时正确解释文本为字符串,B)引用数据中存在的任何
'
。然后使用
JSON.parse()
将数据返回到内容脚本中的字符串。虽然此编码不是严格要求的,但这是一个好主意,因为您不知道要发送到内容脚本的值的内容。这个值很容易成为导致注入的代码损坏的东西(例如用户可能在输入的文本中使用
'
和/或
"
)。如果您没有以某种方式转义该值,则存在安全漏洞,可能会导致执行任意代码。
从你的弹出脚本:
- 注入一个简单的代码片段,将数据存储在变量中。
- 在 MDN 的
chrome.tabs.executeScript()
回调函数中,调用 tabs.executeScript()
来注入你的脚本(注意:只要它们对于 runAt
具有相同的值,tabs.executeScript()
将按照你调用 tabs.executeScript()
的顺序执行脚本。因此,严格来说,等待小 code
的回调并不是必需的)。
var updateTextTo = document.getElementById('comments').value;
chrome.tabs.executeScript({
code: "var newText = JSON.parse('"
+ JSON.stringify(updateTextTo).replace(/\\/g,'\\\\').replace(/'/g,"\\'") + "';"
}, function () {
chrome.tabs.executeScript({
file: "content_script3.js"
});
});
从您的内容脚本:
- 使用存储在变量中的数据对DOM进行更改
if (typeof newText === 'string') {
Array.from(document.querySelectorAll('textarea.comments')).forEach(el => {
el.value = newText;
});
}
请参见:注释1、2和3。
使用消息传递(MDN)(在内容脚本注入后发送数据)
这需要您的内容脚本代码安装一个侦听器,以便接收弹出窗口或者后台脚本发送的消息(如果与UI的交互导致弹出窗口关闭)。这会稍微复杂一些。
从您的弹出窗口脚本中:
- 使用
tabs.query()
(MDN) 确定活动选项卡。
- 调用
tabs.executeScript()
(MDN)。
- 在
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)添加监听器。
- 退出主要代码,使监听器保持活动状态。如果选择,您可以返回一个成功指示器。
- 收到带有数据的消息后:
- 对DOM进行更改
- 删除您的
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);
}
参见:注1和注2。
注意1:如果您不需要多次使用并且正在使用支持它的浏览器版本(Chrome >= version 45,Firefox >= 32),那么使用Array.from()
是可以的。在Chrome和Firefox中,与从NodeList获取数组的其他方法相比,Array.from()
速度较慢。为了更快速、更兼容地将其转换为数组,您可以使用这个答案中的asArray()
代码。该答案提供的第二个版本的asArray()
也更加健壮。
注意2:如果你愿意
将你的代码限制在Chrome版本>=51或Firefox版本>=50,Chrome从v51开始为
NodeLists提供了
forEach()
方法。因此,你不需要转换为数组。当然,如果你使用不同类型的循环,也不需要转换为数组。
注意3:虽然我以前在自己的代码中使用过这种方法(通过注入带有变量值的脚本),但当阅读
这个答案时,我被提醒应该在这里包含它。
<textarea>
的内容。这真的是你想问的吗?顺便说一下:你的选择器最好写成'textarea.comments'
。目前你获取的是所有具有该类的元素,而不仅仅是<textarea class="comments">
。 - Makyen