【问题标题】:How do I access an iframe's javascript from a userscript?如何从用户脚本访问 iframe 的 javascript?
【发布时间】:2012-07-23 05:27:22
【问题描述】:

我正在尝试使用 Chrome 用户脚本或 Tampermonkey 脚本来修改具有此结构的页面:

<body>
content up here

<iframe id="main" src="foo.dat"></iframe>
</body>

iframe 是同源的。

我需要访问iframe#main 中的函数。我以为我可以使用unsafeWindow 来获取它,但我一直没有得到任何东西或undefined 返回。

我尝试了很多方法:

  • 尝试在iframe 中创建新的脚本元素,但即使使用$('frame#main').contents().append(script)$('frame#main').contents()[0].createElement('script'),它也会附加到父元素

  • window.frames["#main"].contentWindow 返回未定义。

我已经尝试了许多其他我现在不记得的事情,但是我已经用尽了所有的想法,并且觉得我在打字比任何重要的东西都多。
我不知道如何使用 iFrame 的unsafeWindow

【问题讨论】:

    标签: javascript google-chrome iframe greasemonkey tampermonkey


    【解决方案1】:
    1. unsafeWindow 在 Chrome、Tampermonkey 或 Firefox 上不能很好地处理帧/iframe。
    2. 尝试使用 jQuery 访问全局(到框架)JS 是行不通的。
    3. 用户脚本将在满足 @include@exclude 和/或 @match 要求的 iframe 上运行。

    因此,您需要考虑多个脚本运行,然后您有两种基本方法,具体取决于您要完成的任务。你可以:

    (A) 为特定帧定制脚本,如this answer

    或 (B) 注入您的 JS 并使用特殊的 frames 对象来获取您想要的特定功能。

    以下脚本演示了两者。在 Tampermonkey1(或 Firefox Greasemonkey)中安装它,然后访问this test page at jsBin

    // ==UserScript==
    // @name        _Calling iframe functions
    // @namespace   _pc
    // @include     http://jsbin.com/ugoruz/*
    // @include     http://jsbin.com/okequw/*
    // ==/UserScript==
    
    console.log ("Script start...");
    
    /*--- This next function call will work in Firefox or Tampermonkey ONLY,
        not pure Chrome userscript.
    */
    console.log ("calling functionOfInterest ()...");
    unsafeWindow.functionOfInterest ();
    
    
    if (window.top === window.self) {
        //--- Code to run when page is the main site...
        console.log ("Userscript is in the MAIN page.");
    
        //--- The frames object does not play nice with unsafeWindow.
        /*--- These next three work in Firefox, but not Tampermonkey, nor pure Chrome.
        console.log ("1", frames[1].variableOfInterest);                // undefined
        console.log ("2", unsafeWindow.frames[1].variableOfInterest);   // undefined
        console.log ("3", frames[1].unsafeWindow);                      // undefined
        */
        /*--- This next would cause a silent crash, all browsers...
        console.log ("4", unsafeWindow.frames[1].unsafeWindow.variableOfInterest);
        */
    
        //--- To get at iFramed JS, we must inject our JS.
        withPages_jQuery (demoAccessToFramedJS);
    }
    else {
        //--- Code to run when page is in an iframe...
        console.log ("Userscript is in the FRAMED page.");
        console.log ("The frame's ID is:", window.self.frameElement.id);
    }
    
    
    function demoAccessToFramedJS ($) {
        $("body").prepend (
              '<button id="gmMain">Run JS on main window</button>'
            + '<button id="gmFrame">Run JS on iframe</button>'
        );
    
        $("#gmMain, #gmFrame").click ( function () {
            if (this.id === "gmMain") {
                functionOfInterest ();
            }
            else {
                frames[1].functionOfInterest ();
            }
            console.log (this.id + "was clicked.");
        } );
    }
    
    function withPages_jQuery (NAMED_FunctionToRun) {
        //--- Use named functions for clarity and debugging...
        var funcText        = NAMED_FunctionToRun.toString ();
        var funcName        = funcText.replace (/^function\s+(\w+)\s*\((.|\n|\r)+$/, "$1");
        var script          = document.createElement ("script");
        script.textContent  = funcText + "\n\n";
        script.textContent += 'jQuery(document).ready(function() {'+funcName+'(jQuery);});';
        document.body.appendChild (script);
    };
    
    console.log ("Script end");
    



    您将看到该脚本从主页和 iframe 运行一个函数。控制台输出(Tampermonkey)将是:

    Tampermonkey 开始 脚本开始... 调用functionOfInterest()... 用户脚本位于 MAIN 页面中。 脚本结束 Tampermonkey 开始 脚本开始... 调用functionOfInterest()... 用户脚本位于 FRAMED 页面中。 框架的 ID 是:iframe2 脚本结束

    1 如果您删除 unsafeWindow 行,它也可以直接用作 Chrome 用户脚本。

    【讨论】:

    • 好吧,您提出的内容对我来说并不完全有效,但这与您引用的答案相结合是有效的。基本上,正如您所建议的,我最终做的是在两个框架中都包含脚本,但仅根据脚本的加载位置执行部分脚本。有点笨拙的解决方法,但在这一点上,我会采取任何措施。谢谢。
    • 我认为要使这个脚本正常工作,您需要在其元数据块中更改这些行:// @include http://*.jsbin.com/ugoruz/*// @include http://*.jsbin.com/okequw/*
    猜你喜欢
    • 2010-10-30
    • 1970-01-01
    • 2011-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多