从 Chrome 上的 Greasemonkey 脚本将 JS 函数注入页面
我有一个 Greasemonkey 脚本,可以在 Firefox 和 Opera 中正常运行。然而,我很难让它在 Chrome 中工作。问题是将一个函数注入到页面中,该函数可以由页面中的代码调用。到目前为止我正在做的事情如下:
首先,我获得了对 Firefox 的 unsafeWindow 的帮助器引用。这使我能够为 FF 和 Opera(以及 Chrome,我认为)拥有相同的代码。
var uw = (this.unsafeWindow) ? this.unsafeWindow : window;
接下来,我将一个函数注入到页面中。它实际上只是一个非常薄的包装器,除了在我的 GM 脚本上下文中调用相应的函数之外什么也不做:
uw.setConfigOption = function(newValue) {
setTimeout(setConfigOption, 0, newValue);
}
然后,我的脚本中就有相应的函数:
setConfigOption = function(newValue) {
// do something with it, e.g. store in localStorage
}
最后,我将一些 HTML 注入到页面中,并带有一个调用该函数的链接。
var p = document.createElement('p');
p.innerHTML = '<a href="javascript:setConfigOption(1)">set config option to 1</a>';
document.getElementById('injection-point').appendChild(p);
总结一下: 在 Firefox 中,当用户单击该注入的链接时,它将在 unsafeWindow 上执行函数调用,然后触发超时,在我的 GM 脚本上下文中调用相应的函数,然后执行实际处理。 (如果我错了,请纠正我。)
在 Chrome 中,我只是收到“未捕获的引用错误:setConfigOption 未定义”错误。事实上,在控制台中输入“window.setConfigOption”会产生“未定义”。在Firebug和Opera开发者控制台中,都有该功能。
也许还有另一种方法可以做到这一点,但是我的一些函数是由页面上的 Flash 对象调用的,我认为这使得我有必要在页面上下文中拥有函数。
我快速浏览了 Greasemonkey wiki 上的 unsafeWindow 的替代品,但它们看起来都一样很丑。我在这里完全走错了路还是我应该更仔细地研究这些?
解决方案:我遵循了最大 S。'建议,它现在可以在 Firefox 和 Chrome 中使用。因为我需要对页面可用的函数必须回调到常规函数,所以我将整个脚本移至页面,即它完全包装到他称为“main()”的函数中。
为了让这个额外的丑陋的黑客行为变得更容易忍受,我现在至少可以放弃使用 unsafeWindow 和wrappedJSObject。
我仍然没有设法让 Greasemonkey wiki 中的 内容范围运行程序 正常工作。它应该做同样的事情,而且似乎执行得很好,但例如,我的函数永远无法被页面中的 元素访问。我还没弄清楚这是为什么。
I have a Greasemonkey script that works just fine in Firefox and Opera. I struggle with getting it to work in Chrome, however. The problem is injecting a function into the page that can be invoked by code from the page. Here's what I'm doing so far:
First, I get a helper reference to the unsafeWindow for Firefox. This allows me to have the same code for FF and Opera (and Chrome, I thought).
var uw = (this.unsafeWindow) ? this.unsafeWindow : window;
Next, I inject a function into the page. It's really just a very thin wrapper that does nothing but invoking the corresponding function in the context of my GM script:
uw.setConfigOption = function(newValue) {
setTimeout(setConfigOption, 0, newValue);
}
Then, there's the corresponding function right in my script:
setConfigOption = function(newValue) {
// do something with it, e.g. store in localStorage
}
Last, I inject some HTML into the page with a link to invoke the function.
var p = document.createElement('p');
p.innerHTML = '<a href="javascript:setConfigOption(1)">set config option to 1</a>';
document.getElementById('injection-point').appendChild(p);
To summarize:
In Firefox, when the user clicks that injected link, it will execute the function call on the unsafeWindow, which then triggers a timeout that invokes the corresponding function in the context of my GM script, which then does the actual processing. (Correct me if I'm wrong here.)
In Chrome, I just get a "Uncaught ReferenceError: setConfigOption is not defined" error. And indeed, entering "window.setConfigOption" into the console yields an "undefined". In Firebug and the Opera developer console, the function is there.
Maybe there's another way to do this, but a few of my functions are invoked by a Flash object on the page, which I believe makes it necessary that I have functions in the page context.
I took a quick look at the alternatives to unsafeWindow on the Greasemonkey wiki, but they all look pretty ugly. Am I completely on the wrong track here or should I look more closely into these?
RESOLUTION: I followed Max S.' advice and it works in both Firefox and Chrome now. Because the functions I needed to be available to the page had to call back into the regular ones, I moved my whole script to the page, i.e. it is completely wrapped into the function he called 'main()'.
To make the extra uglyness of that hack a little bit more bearable, I could at least drop the usage of unsafeWindow and wrappedJSObject now.
I still haven't managed to get the content scope runner from the Greasemonkey wiki working. It should do the same and it seems to execute just fine, but my functions are never accessible to <a>
elements from the page, for example. I haven't yet figured out why that is.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
与 Chrome 页面上运行的代码进行通信的唯一方法是通过 DOM,因此您必须使用一些技巧,例如在代码中插入
标记。请注意,如果您的脚本需要在页面上的其他所有内容之前运行,这可能会出现错误。
编辑:Nice Alert 扩展程序执行此操作的方式如下:
The only way to communicate with the code running on the page in Chrome is through the DOM, so you'll have to use a hack like inserting a
<script>
tag with your code. Note that this may prove buggy if your script needs to run before everything else on the page.EDIT: Here's how the Nice Alert extension does this:
我有这个:
contentscript.js:
injected.js:
I have this :
contentscript.js :
injected.js :
其他答案要么强制您使用 函数表达式,导入 外部附加文件或使用长补丁黑客。
此答案将直接从源代码将 JavaScript 添加到页面中。它将使用 ECMAScript 6 (ES6) 模板文字轻松地将多行 JavaScript 字符串放到页面上。
请注意反引号
``
定义多行字符串的开头和结尾。The other answers either force you to use function expressions, import an external additional file or use a long patched hack.
This answer will add the javascript into the page directly from your source code. It will use ECMAScript 6 (ES6) template literals to get the multi-line javascript string effortlessly onto the page.
Please note the backticks
``
that define the beginning and the end of a multi-line string.你应该看看,因为这是唯一可用的选择。我更喜欢使用位置黑客。
myscript.user.js:
example.com/mypage.html
当然,它很丑。但效果很好。
Max S.提到的Content Scope Runner方法比location hack更好,因为它更容易调试。
You should look, because it's only available option. I'd prefer to use location hack.
myscript.user.js:
example.com/mypage.html
Sure, it's ugly. But it's working well.
Content Scope Runner method, mentioned by Max S. is better than location hack, because its easier to debug.