【问题标题】:Bind document.ready to a popout window将 document.ready 绑定到弹出窗口
【发布时间】:2011-11-16 21:01:12
【问题描述】:

由于 jQuery 绑定 document.ready 事件的方式,应该简单的代码不是:

var w = window.open(someSameOriginLocation,'');
$(w).ready(function () { //alternatively selector could be $(w.document)
  console.log('popout ready');
});

问题

  • 回调在父窗口就绪时执行,而不是子窗口
  • 在回调中this 是对w.opener.document 的引用

是否有一种相当简单的跨浏览器方法可以使用 jQuery 将 ready 事件(或类似事件)绑定到不同的窗口上下文?

【问题讨论】:

  • 也许与 jQuery .live 函数和 'load' 事件有关
  • @HerrSerker, live 只是将事件绑定到活动的document。我可以使用 $(w).popupready(fn); 之类的自定义绑定函数,我只是不想重新发明轮子。

标签: javascript jquery document-ready


【解决方案1】:

大约 5 年前,当我问这个问题时,我还没有听说过 Promise。 jQuery 1.7 最近发布了,Deferred 在今年早些时候的 1.5 中被引入。这早于一年多后发布的Promises/A+ 规范。

我之所以这么说,是因为当时我无法识别 jQuery 的 $(document).ready(...) 到底是什么。

它被绑定为一个事件,并将回调作为一个事件,而jQuery API将其视为一个事件,所以我错误地认为它是一个事件,尽管是一个特殊的事件。

准备好文档不是一个事件。 这是一个承诺。

话虽如此,我的错误在于试图跟随 jQuery 的领导并创建一个奇特的事件,而我应该做的是使用一个 Promise(别介意它们在 JS 世界中还不存在)。


话虽如此,在现代浏览器的任何窗口引用上支持类似document.ready 的行为非常简单。我有时间优势,很多老问题已经被修正了,新的浏览器特性(比如Promise)大大减少了实现ready函数的工作量。

我对这个问题的解决方案如下:

function ready(win) {
    return new Promise(function (resolve) {
        function checkReady() {
            if (win.document.readyState === 'complete') {
                resolve();
            }
        }

        win.document.addEventListener('DOMContentLoaded', checkReady, false);
        win.addEventListener('load', checkReady, false);
        checkReady();
    });
}

并且可以用作:

ready(window).then(function () {
  //...do stuff
});

或者如果您使用的是window.open

ready(open('/your/file.html', ...)).then(function () {
  //.../your/file.html is ready
});

【讨论】:

    【解决方案2】:

    JavaScript 安全策略不允许这样做。例如你得到控制台错误

    Unsafe JavaScript attempt to access frame with URL http://www.example.com/ from frame with URL http://www.example.org/. Domains, protocols and ports must match.
    

    在调用 window.open 和设置同一个窗口的 onload 函数之间有必要暂停一下。在 window.open 调用之后,该窗口立即没有属性。也许您必须反复使用 setInterval 执行此操作(然后不要忘记 clearInterval)
    在 jsfiddle 中试试这个(这是我最好的猜测)

    function func() {
    
        var w = window.open('http://fiddle.jshell.net/','windowname');
    
        setTimeout(function() {
            w.onload = function () {
                $(w).ready(function() {
                    console.log(w.name)
                });
            };
        },1000)
    }
    

    http://jsfiddle.net/HerrSerker/fTjTr/8/

    【讨论】:

    • 您需要复习您的安全沙盒知识。除了任何非内容页面之外,页面还被授予访问同一域 (same-origin policy) 的子页面的权限。您不能将位置更改为 http://www.example.com/' 并期望它能够正常工作。我的示例代码运行良好(除了ready 没有绑定到正确的窗口上下文)。
    • @zzzzBov 你的代码没有运行,因为你没有加载任何页面。所以没有 DOMready 会触发。我不知道你在同一个域中。那你为什么不在加载的窗口中触发$(document).ready 并依赖window.opener.document
    • 您显然错过了问题的重点。 window.open('','') 可以是 window.open('foo.html'),我希望父页面在加载的页面(是否为空)完全准备好时进行回调。我一直在检查 jQuery 源代码,看起来创建自己的通用事件不会困难,我只是希望其他人已经拥有。
    • 设置单个 onload 事件远不及 jQuery 中 document.ready 调用的功能。
    • 你所做的改变是猪的口红。您没有更改脚本的任何核心问题,实际上使情况变得更糟,因为您根本不了解 jQuery 如何管理 .ready() 函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多