用户脚本& Greasemonkey:调用网站的JavaScript函数

时间:2011-02-15 16:32:41

标签: javascript google-chrome-extension greasemonkey userscripts

我正在为Firefox&创建一个UserScript扩展程序。 Chrome和我正在尝试使用网站JavaScript中的一些代码,例如:

function: myFunction(){
    return  Grooveshark.playNextSong();
}

问题是当我测试此代码时,Grooveshark是一个空引用。

我知道还有其他人做过:

see BetterGrooveshark

但我不知道为什么我的简单扩展无法调用Grooveshark的JavaScript函数。

我是否需要将我的脚本'追加'到文档中才能使其正常工作?: document.document.body.appendChild(script);

Greasemonkey不会注入我的扩展JavaScript吗?有人可以帮我解释一下。

感谢。

2 个答案:

答案 0 :(得分:72)

背景

  

Greasemonkey不会注入我的扩展JavaScript吗?有人可以帮我解释一下。

Greasemonkey在sandbox中执行您的脚本,这是一个受限制的环境,无法直接访问页面中的JavaScript。早期版本的Greasemonkey将脚本直接注入页面,但这引入了严重的安全漏洞。在旧模型中,脚本使用浏览器chrome的提升权限运行,这允许远程页面使用某些clever JavaScript访问Greasemonkey的内置函数。这很糟糕:

  

Greasemonkey脚本包含自己的GM_xmlhttprequest对象,与普通的xmlttprequest对象不同,它可以访问任何本地文件,或者对任意站点发出任意请求,而不考虑通常适用于xmlhttprequest的相同源策略。 (source)

今天从Greasemonkey脚本访问window对象时,得到的是wrapper object间接引用实际window属性的内容。可以安全地修改此包装器对象,但具有important limitationsunsafeWindowwindow.wrappedJSObject的简写)提供对实际窗口对象的访问。使用unsafeWindow会重新打开Greasemonkey的所有原始安全问题,但在Chrome中无法使用。应尽可能避免使用。

好消息:至少有两种方法可以安全地使用Greasemonkey的新安全模型。

脚本注入

现在Greasemonkey脚本可以安全地访问DOM,inject a <script>标记到目标文档的<head>是微不足道的。创建一个这样的函数:

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
}

使用简单:

exec(function() {
    return Grooveshark.playNextSong();
});

位置黑客

在某些情况下,脚本注入可能过度,特别是当你需要的是修改页面中变量的值或执行单个函数时。 Location Hack利用javascript:网址访问文档内容中的代码。这很像在Greasemonkey脚本中运行bookmarklet。

location.assign("javascript:Grooveshark.playNextSong();void(0)");

奖金脚本

这是一个完整的Greasemonkey脚本,演示了上面的示例。您可以在此页面上运行它。

// ==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);

答案 1 :(得分:11)

由于显而易见的原因,GreaseMonkey脚本中声明的函数和变量(以及Chrome的用户脚本)与网页声明的函数和变量保持独立。对于Firefox中的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);