我正在为火狐和Chrome创建一个UserScript扩展,并尝试使用网站的JavaScript中的一些代码,例如:
function: myFunction(){
return Grooveshark.playNextSong();
}问题是,当我测试这段代码时,Grooveshark是一个空引用。
我知道还有其他人也这么做过:
see BetterGrooveshark
但是我不知道为什么我的简单扩展不能调用Grooveshark的JavaScript函数。
我需要将我的脚本‘附加’到文档中才能正常工作吗?:document.document.body.appendChild(script);
Greasemonkey不是已经注入我的扩展JavaScript了吗?有人能帮我澄清一下吗?
谢谢。
发布于 2011-02-16 01:11:26
背景
不是已经在注入我的扩展JavaScript了吗?有人能帮我澄清一下吗?
Greasemonkey在sandbox中执行脚本,这是一个受限制的环境,不能直接访问页面中的JavaScript。早期版本的Greasemonkey直接将脚本注入到页面中,但这引入了严重的安全漏洞。在旧的模型中,脚本以浏览器chrome的提升权限运行,这允许远程页面使用一些clever JavaScript访问Greasemonkey的内置功能。这很糟糕:
xmlhttprequest脚本包含自己的GM_xmlhttprequest对象,与普通的xmlhttprequest对象不同,该对象可以访问计算机上的任何本地文件或向任意站点发出任意请求,而无需考虑通常应用于xmlhttprequest的同源策略。(source)
今天,当你从Greasemonkey脚本访问window对象时,你得到的是一个间接引用实际window属性的wrapper object。这个包装器对象可以安全地修改,但具有important limitations。对实际窗口对象的访问是由unsafeWindow (window.wrappedJSObject的简写)提供的。使用unsafeWindow会重新打开所有Greasemonkey的原始安全问题,并且在Chrome中不可用。应该尽可能避免这种情况。
好消息是:至少有两种方法可以安全地使用Greasemonkey的新安全模型。
脚本注入
既然Greasemonkey脚本可以安全地访问DOM,那么将inject a </code></a>标记添加到目标文档的<code><head></code>中就很简单了。创建如下所示的函数:</div><pre><code>function exec(fn) { var script = document.createElement('script'); script.setAttribute("type", "application/javascript"); script.textContent = '(' + fn + ')();'; document.body.appendChild(script); // run the script document.body.removeChild(script); // clean up }</code></pre><div>它使用起来很简单:</div><pre><code>exec(function() { return Grooveshark.playNextSong(); });</code></pre><div>位置Hack</div><div>脚本注入在某些情况下可能过于夸张,特别是当您所需要的只是修改页面中变量的值或执行单个函数时。<a href="http://wiki.greasespot.net/Location_hack">Location Hack</a>利用<code>javascript:</code> URL访问文档内容中的代码。这很像是在一个Greasemonkey脚本中运行一个bookmarklet。</div><pre><code>location.assign("javascript:Grooveshark.playNextSong();void(0)");</code></pre><div>奖励脚本</div><div>下面是一个完整的Greasemonkey脚本,它演示了上面的示例。您可以在此页面上运行它。</div><pre><code>// ==UserScript== // @name Content Function Test // @namespace lwburk // @include http://stackoverflow.com/questions/5006460/userscripts-greasemonkey-calling-a-websites-javascript-functions // ==/UserScript== function exec(fn) { var script = document.createElement('script'); script.setAttribute("type", "application/javascript"); script.textContent = '(' + fn + ')();'; document.body.appendChild(script); // run the script document.body.removeChild(script); // clean up } window.addEventListener("load", function() { // script injection exec(function() { // alerts true if you're registered with Stack Overflow alert('registered? ' + isRegistered); }); // location hack location.assign("javascript:alert('registered? ' + isRegistered);void(0)"); }, false);</code></pre><div></div>
发布于 2011-02-16 00:42:18
由于显而易见的原因,你的GreaseMonkey脚本(和Chrome的用户脚本)中声明的函数和变量与网页声明的函数和变量是分开的。对于火狐中的GM脚本,您可以通过unsafeWindow访问全局变量。
为了安全和兼容,最好的方法是使用脚本元素将函数注入页面。 我在用户脚本中使用以下代码片段:
function addFunction(func, exec) {
var script = document.createElement("script");
script.textContent = "-" + func + (exec ? "()" : "");
document.body.appendChild(script);
}这里的"-"确保函数被解析为表达式,以便在添加函数时可以使用exec立即执行。 您可以像这样调用函数:
function myFunction () {
return Grooveshark.playNextSong();
}
// Inject the function and execute it:
addFunction(myFunction, true);https://stackoverflow.com/questions/5006460
复制相似问题