首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何检测何时已加载iframe

如何检测何时已加载iframe
EN

Stack Overflow用户
提问于 2013-06-18 08:31:34
回答 8查看 23.7K关注 0票数 37

如果在iframe加载完成后附加了$('#someIframe').load(function(){...}),那么它似乎不会触发。对吗?

我真正想要的是有一个函数,它总是在加载iframe时或之后调用一次。为了让这一点更清楚,这里有两个案例:

  • Iframe尚未加载回调:一旦loads.
  • Iframe已加载,立即运行回调函数:立即运行

我该怎么做呢?

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2016-03-22 21:23:14

我一直把头撞在墙上,直到弄清楚这里发生了什么。

背景信息

如果已经加载了iframe,则使用.load()

  • 是不可能的(事件将永远不会触发)不支持在iframe元素上使用.ready()
  • (reference),并将立即调用回调,即使未加载iframe,但使用postMessage或在iframe内的load上调用容器函数的
  • 仅当在容器上使用$(window).load()
  • 将等待其他资产加载时才可能。如果你只想在Chrome中等待一个特定的iframe
  • Checking readyState,这不是一个解决方案,因为一个alredy触发的onload事件是没有意义的,因为Chrome会用一个“about:空白”的空白页面初始化每个iframe。此页的readyState可能是complete,但它不是您期望的页的readyState (src属性)。

解决方案

以下内容是必需的:

如果iframe还没有加载,我们可以观察到iframe的事件。如果iframe已经加载,我们需要检查readyState

  • If
  1. is readyState is complete,我们通常可以假定iframe已经加载。然而,由于Chrome的上述行为,我们还需要检查它是否是空页面的readyState
  2. ,如果是,我们需要以一定的间隔观察readyState,以检查实际文档(与src属性相关)是否为Chrome

我已经用下面的函数解决了这个问题。它已经(转译为ES5)在

  • Chrome 49
  • Safari 5
  • Firefox 45
  • IE 8,9,10,11
  • Edge 24
  • iOS 8.0 ("Safari Chrome 4.0 (“浏览器”)

取自 的函数

代码语言:javascript
复制
/**
 * Will wait for an iframe to be ready
 * for DOM manipulation. Just listening for
 * the load event will only work if the iframe
 * is not already loaded. If so, it is necessary
 * to observe the readyState. The issue here is
 * that Chrome will initialize iframes with
 * "about:blank" and set its readyState to complete.
 * So it is furthermore necessary to check if it's
 * the readyState of the target document property.
 * Errors that may occur when trying to access the iframe
 * (Same-Origin-Policy) will be catched and the error
 * function will be called.
 * @param {jquery} $i - The jQuery iframe element
 * @param {function} successFn - The callback on success. Will 
 * receive the jQuery contents of the iframe as a parameter
 * @param {function} errorFn - The callback on error
 */
var onIframeReady = function($i, successFn, errorFn) {
    try {
        const iCon = $i.first()[0].contentWindow,
            bl = "about:blank",
            compl = "complete";
        const callCallback = () => {
            try {
                const $con = $i.contents();
                if($con.length === 0) { // https://git.io/vV8yU
                    throw new Error("iframe inaccessible");
                }
                successFn($con);
            } catch(e) { // accessing contents failed
                errorFn();
            }
        };
        const observeOnload = () => {
            $i.on("load.jqueryMark", () => {
                try {
                    const src = $i.attr("src").trim(),
                        href = iCon.location.href;
                    if(href !== bl || src === bl || src === "") {
                        $i.off("load.jqueryMark");
                        callCallback();
                    }
                } catch(e) {
                    errorFn();
                }
            });
        };
        if(iCon.document.readyState === compl) {
            const src = $i.attr("src").trim(),
                href = iCon.location.href;
            if(href === bl && src !== bl && src !== "") {
                observeOnload();
            } else {
                callCallback();
            }
        } else {
            observeOnload();
        }
    } catch(e) { // accessing contentWindow failed
        errorFn();
    }
};

工作示例

由两个文件(index.html和iframe.html)组成:index.html

代码语言:javascript
复制
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>Parent</title>
</head>
<body>
    <script src="https://code.jquery.com/jquery-1.12.2.min.js"></script>
    <script>
        $(function() {

            /**
             * Will wait for an iframe to be ready
             * for DOM manipulation. Just listening for
             * the load event will only work if the iframe
             * is not already loaded. If so, it is necessary
             * to observe the readyState. The issue here is
             * that Chrome will initialize iframes with
             * "about:blank" and set its readyState to complete.
             * So it is furthermore necessary to check if it's
             * the readyState of the target document property.
             * Errors that may occur when trying to access the iframe
             * (Same-Origin-Policy) will be catched and the error
             * function will be called.
             * @param {jquery} $i - The jQuery iframe element
             * @param {function} successFn - The callback on success. Will 
             * receive the jQuery contents of the iframe as a parameter
             * @param {function} errorFn - The callback on error
             */
            var onIframeReady = function($i, successFn, errorFn) {
                try {
                    const iCon = $i.first()[0].contentWindow,
                        bl = "about:blank",
                        compl = "complete";
                    const callCallback = () => {
                        try {
                            const $con = $i.contents();
                            if($con.length === 0) { // https://git.io/vV8yU
                                throw new Error("iframe inaccessible");
                            }
                            successFn($con);
                        } catch(e) { // accessing contents failed
                            errorFn();
                        }
                    };
                    const observeOnload = () => {
                        $i.on("load.jqueryMark", () => {
                            try {
                                const src = $i.attr("src").trim(),
                                    href = iCon.location.href;
                                if(href !== bl || src === bl || src === "") {
                                    $i.off("load.jqueryMark");
                                    callCallback();
                                }
                            } catch(e) {
                                errorFn();
                            }
                        });
                    };
                    if(iCon.document.readyState === compl) {
                        const src = $i.attr("src").trim(),
                            href = iCon.location.href;
                        if(href === bl && src !== bl && src !== "") {
                            observeOnload();
                        } else {
                            callCallback();
                        }
                    } else {
                        observeOnload();
                    }
                } catch(e) { // accessing contentWindow failed
                    errorFn();
                }
            };

            var $iframe = $("iframe");
            onIframeReady($iframe, function($contents) {
                console.log("Ready to got");
                console.log($contents.find("*"));
            }, function() {
                console.log("Can not access iframe");
            });
        });
    </script>
    <iframe src="iframe.html"></iframe>
</body>
</html>

iframe.html

代码语言:javascript
复制
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>Child</title>
</head>
<body>
    <p>Lorem ipsum</p>
</body>
</html>

您还可以将index.html中的src属性更改为例如"http://example.com/“。玩它就好了。

票数 50
EN

Stack Overflow用户

发布于 2013-06-18 15:29:52

我会使用postMessage。iframe可以将它自己的onload事件和post分配给父对象。如果存在计时问题,只需确保在创建iframe之前分配父进程的postMessage处理程序。

为此,iframe必须知道父元素的url,例如通过向iframe传递GET参数。

票数 3
EN

Stack Overflow用户

发布于 2019-01-28 17:46:12

我也有同样的问题。在我的例子中,我只是简单地检查了onload函数是否被触发。

代码语言:javascript
复制
var iframe = document.getElementById("someIframe");
var loadingStatus = true;
iframe.onload = function () {
    loadingStatus = false;
    //do whatever you want [in my case I wants to trigger postMessage]
};
if (loadingStatus)
    //do whatever you want [in my case I wants to trigger postMessage]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17158932

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档