问题描述
这是我的 contentScript.js 中的代码:
function loadScript(script_url)
{
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.src= chrome.extension.getURL('mySuperScript.js');
head.appendChild(script);
someFunctionFromMySuperScript(request.widgetFrame);// ReferenceError: someFunctionFromMySuperScript is not defined
}
但是从注入的脚本调用函数时出现错误:
but i got an error when calling a function from injected script:
参考错误:未定义someFunctionFromMySuperScript
是否可以在不修改 mySuperScript.js 的情况下调用此函数?
Is there is a way to call this function without modifying mySuperScript.js?
推荐答案
您的代码有多个问题:
- 您已经注意到,来自注入脚本(mySuperScript.js)的函数和变量对于内容脚本(contentScript.js)不直接可见.这是因为这两个脚本在不同的执行环境中运行.
- 使用通过
src
属性引用的脚本插入< script>
元素不会立即导致脚本执行.因此,即使脚本在同一环境中运行,也仍然无法访问它.
- As you've noticed, the functions and variables from the injected script (mySuperScript.js) are not directly visible to the content script (contentScript.js). That is because the two scripts run in different execution environments.
- Inserting a
<script>
element with a script referenced through asrc
attribute does not immediately cause the script to execute. Therefore, even if the scripts were to run in the same environment, then you can still not access it.
要解决此问题,请首先考虑是否真的有必要在页面中运行 mySuperScript.js
.如果您不从页面本身访问任何JavaScript对象,则无需注入脚本.您应该尽量减少在页面本身中运行的代码量,以免发生冲突.
To solve the issue, first consider whether it is really necessary to run mySuperScript.js
in the page. If you don't to access any JavaScript objects from the page itself, then you don't need to inject a script. You should try to minimize the amount of code that runs in the page itself to avoid conflicts.
如果您不必运行页面中的代码,请先在 contentScript.js
之前运行 mySuperScript.js
,然后任何功能和变量都将立即可用(通常,通过清单或通过程序化注入).如果出于某种原因确实需要动态加载脚本,则可以在 web_accessible_resources中声明它
并使用 获取
或 XMLHttpRequest
加载脚本,然后 eval
以在您的内容脚本的上下文中运行它.
If you don't have to run the code in the page, then run mySuperScript.js
before contentScript.js
, and then any functions and variables are immediately available (as usual, via the manifest or by programmatic injection).If for some reason the script really needs to be loaded dynamically, then you could declare it in web_accessible_resources
and use fetch
or XMLHttpRequest
to load the script, and then eval
to run it in your content script's context.
例如:
function loadScript(scriptUrl, callback) {
var scriptUrl = chrome.runtime.getURL(scriptUrl);
fetch(scriptUrl).then(function(response) {
return response.text();
}).then(function(responseText) {
// Optional: Set sourceURL so that the debugger can correctly
// map the source code back to the original script URL.
responseText += '\n//# sourceURL=' + scriptUrl;
// eval is normally frowned upon, but we are executing static
// extension scripts, so that is safe.
window.eval(responseText);
callback();
});
}
// Usage:
loadScript('mySuperScript.js', function() {
someFunctionFromMySuperScript();
});
如果确实需要从脚本中调用页面中的函数(即 mySuperScript.js
必须绝对在页面的上下文中运行),则可以注入另一个脚本(通过以下任何一种方式)来自构建Chrome扩展程序-使用内容脚本在页面中插入代码),然后将消息传递回内容脚本(例如).
If you really have to call a function in the page from the script (i.e. mySuperScript.js
must absolutely run in the context of the page), then you could inject another script (via any of the techniques from Building a Chrome Extension - Inject code in a page using a Content script) and then pass the message back to the content script (e.g. using custom events).
例如:
var script = document.createElement('script');
script.src = chrome.runtime.getURL('mySuperScript.js');
// We have to use .onload to wait until the script has loaded and executed.
script.onload = function() {
this.remove(); // Clean-up previous script tag
var s = document.createElement('script');
s.addEventListener('my-event-todo-rename', function(e) {
// TODO: Do something with e.detail
// (= result of someFunctionFromMySuperScript() in page)
console.log('Potentially untrusted result: ', e.detail);
// ^ Untrusted because anything in the page can spoof the event.
});
s.textContent = `(function() {
var currentScript = document.currentScript;
var result = someFunctionFromMySuperScript();
currentScript.dispatchEvent(new CustomEvent('my-event-todo-rename', {
detail: result,
}));
})()`;
// Inject to run above script in the page.
(document.head || document.documentElement).appendChild(s);
// Because we use .textContent, the script is synchronously executed.
// So now we can safely remove the script (to clean up).
s.remove();
};
(document.head || document.documentElement).appendChild(script);
(在上面的示例中,我使用的是模板文字,Chrome 41+支持此功能)
(in the above example I'm using template literals, which are supported in Chrome 41+)
这篇关于如何从注入的脚本中调用函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!