简体   繁体   English

在 Chrome 中加载 iframe 时不会触发“加载”事件

[英]'load' event not firing when iframe is loaded in Chrome

I am trying to display a 'mask' on my client while a file is dynamically generated server side.我试图在我的客户端上显示一个“掩码”,而文件是动态生成的服务器端。 Seems like the recommend work around for this (since its not ajax) is to use an iframe and listen from the onload or done event to determine when the file has actually shipped to the client from the server.似乎推荐的解决方法(因为它不是 ajax)是使用 iframe 并从 onload 或 done 事件中侦听以确定文件何时从服务器实际发送到客户端。

here is my angular code:这是我的角度代码:

    var url = // url to my api
    var e = angular.element("<iframe style='display:none' src=" + url + "></iframe>");
    e.load(function() {
        $scope.$apply(function() {
            $scope.exporting = false;  // this will remove the mask/spinner
        });
    });
    angular.element('body').append(e);

This works great in Firefox but no luck in Chrome.这在 Firefox 中效果很好,但在 Chrome 中没有运气。 I have also tried to use the onload function:我也尝试过使用 onload 函数:

e.onload = function()  { //unmask here }

But I did not have any luck there either.但我在那里也没有任何运气。

Ideas?想法?

Unfortunately it is not possible to use an iframe's onload event in Chrome if the content is an attachment.不幸的是,如果内容是附件,则无法在 Chrome 中使用 iframe 的onload事件。 This answer may provide you with an idea of how you can work around it.这个答案可能会让您了解如何解决它。

I hate this, but I couldn't find any other way than checking whether it is still loading or not except by checking at intervals.我讨厌这一点,但除了定期检查之外,我找不到任何其他方法,只能检查它是否仍在加载。

var timer = setInterval(function () {
    iframe = document.getElementById('iframedownload');
    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
    // Check if loading is complete
    if (iframeDoc.readyState == 'complete' || iframeDoc.readyState == 'interactive') {
        loadingOff();
        clearInterval(timer);
        return;
    }
}, 4000);

You can do it in another way:你可以用另一种方式做到这一点:

In the main document:在主文档中:

function iframeLoaded() {
     $scope.$apply(function() {
            $scope.exporting = false;  // this will remove the mask/spinner
        });
}

var url = // url to my api
var e = angular.element("<iframe style='display:none' src=" + url + "></iframe>");
angular.element('body').append(e);

In the iframe document (this is, inside the html of the page referenced by url)在 iframe 文档中(即,在 url 引用的页面的 html 中)

    window.onload = function() {
        parent.iframeLoaded();
    }

This will work if the main page, and the page inside the iframe are in the same domain.如果主页和 iframe 内的页面在同一个域中,这将起作用。

Actually, you can access the parent through:实际上,您可以通过以下方式访问父级:

window.parent
parent
//and, if the parent is the top-level document, and not inside another frame
top          
window.top

It's safer to use window.parent since the variables parent and top could be overwritten (usually not intended).使用window.parent更安全,因为变量parenttop可能会被覆盖(通常不是故意的)。

you have to consider 2 points:你必须考虑2点:

1- first of all, if your url has different domain name, it is not possible to do this except when you have access to the other domain to add the Access-Control-Allow-Origin: * header, to fix this go to this link . 1-首先,如果您的 url 具有不同的域名,则无法执行此操作,除非您有权访问其他域以添加Access-Control-Allow-Origin: *标头,要解决此问题,请转到此链接

2- but if it has the same domain or you have added Access-Control-Allow-Origin: * to the headers of your domain, you can do what you want like this: 2-但如果它具有相同的域或者您已将Access-Control-Allow-Origin: *到域的标头中,您可以像这样执行您想要的操作:

var url = // url to my api
var e = angular.element("<iframe style='display:none' src=" + url + "></iframe>");
angular.element(document.body).append(e);
e[0].contentWindow.onload = function() {
    $scope.$apply(function() {
        $scope.exporting = false;  // this will remove the mask/spinner
    });
};

I have done this in all kinds of browsers.我已经在各种浏览器中做到了这一点。

I've just noticed that Chrome is not always firing the load event for the main page so this could have an effect on iframes too as they are basically treated the same way.我刚刚注意到 Chrome 并不总是为主页触发加载事件,因此这也可能对 iframe 产生影响,因为它们基本上以相同的方式处理。

Use Dev Tools or the Performance api to check if the load event is being fired at all.使用 Dev Tools 或 Performance api 检查是否正在触发 load 事件。

I just checked http://ee.co.uk/ and if you open the console and enter window.performance.timing you'll find the entries for domComplete, loadEventStart and loadEventEnd are 0 - at least at this current time:)我刚刚检查了http://ee.co.uk/ ,如果您打开控制台并输入 window.performance.timing,您会发现 domComplete、loadEventStart 和 loadEventEnd 的条目为 0 - 至少在当前时间:)

Looks like there is a problem with Chrome here - I've checked it on 2 PCs using the latest version 31.0.1650.63.看起来这里的 Chrome 有问题 - 我已经使用最新版本 31.0.1650.63 在 2 台 PC 上检查了它。

Update: checked ee again and load event fired but not on subsequent reloads so this is intermittent and may possibly be related to loading errors on their site.更新:再次检查 ee 并触发 load 事件,但不会在随后的重新加载时触发,因此这是间歇性的,可能与他们网站上的加载错误有关。 But the load event should fire whatever.但是加载事件应该触发任何事情。

This problem has occurred on 5 or 6 sites for me now in the last day since I noticed my own site monitoring occasionally failed.自从我注意到我自己的站点监控偶尔会失败以来,这个问题在最后一天发生在我的 5 或 6 个站点上。 Only just pinpointed the cause to this.只是查明了这个原因。 I need some beauty sleep then I'll investigate further when I'm more awake.我需要睡个美容觉,等我更清醒的时候再调查。

I had problems with the iframe taking too long to load.我遇到了 iframe 加载时间过长的问题。 The iframe registered as loaded while the request wasn't handled.在未处理请求时注册为已加载的 iframe。 I came up with the following solution:我想出了以下解决方案:

JS JS

Function:功能:

function iframeReloaded(iframe, callback) {
    let state = iframe.contentDocument.readyState;
    let checkLoad = setInterval(() => {
        if (state !== iframe.contentDocument.readyState) {
            if (iframe.contentDocument.readyState === 'complete') {
                clearInterval(checkLoad);
                callback();
            }
            state = iframe.contentDocument.readyState;
        }
    }, 200)
}

Usage:用法:

iframeReloaded(iframe[0], function () {
    console.log('Reloaded');
})

JQuery查询

Function:功能:

$.fn.iframeReloaded = function (callback) {
    if (!this.is('iframe')) {
        throw new Error('The element is not an iFrame, please provide the correct element');
    }

    let iframe = this[0];
    let state = iframe.contentDocument.readyState;
    let checkLoad = setInterval(() => {
        if (state !== iframe.contentDocument.readyState) {
            if (iframe.contentDocument.readyState === 'complete') {
                clearInterval(checkLoad);
                callback();
            }
            state = iframe.contentDocument.readyState;
        }
    }, 200)
}

Usage:用法:

iframe.iframeReloaded(function () {
    console.log('Reloaded');
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM