【问题标题】:'load' event not firing when iframe is loaded in Chrome在 Chrome 中加载 iframe 时未触发“加载”事件
【发布时间】:2014-01-01 14:09:11
【问题描述】:

我试图在我的客户端上显示一个“掩码”,而文件是在服务器端动态生成的。似乎建议的解决方法(因为它不是 ajax)是使用 iframe 并从 onload 或 done 事件中侦听以确定文件何时从服务器实际发送到客户端。

这是我的角码:

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

这在 Firefox 中效果很好,但在 Chrome 中没有运气。我也尝试过使用 onload 功能:

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

但我在那里也没有运气。

想法?

【问题讨论】:

  • 您是否尝试过将 onload 直接添加到 iframe 的 html 中?过去,我在 Chrome 加载元素和相关事件的顺序方面遇到了一些问题。
  • 是的,刚试过。在 FF 中仍会触发,但在 Chrome 中不会触发。
  • 嗯,网址呢?你不会跨域吧?
  • 想知道服务器设置的标头是否有问题。我正在设置 Content-Type = 'application/zip',并且 Content-Disposition = 'attachment;文件名=temp.zip。不太确定还有什么可能。
  • 这是一个显示问题的插件。在 FF 中运行效果很好,在 Chrome 中运行不是很多:plnkr.co/edit/zkqeAW?p=preview

标签: javascript google-chrome angularjs iframe


【解决方案1】:

很遗憾,如果内容是附件,则无法在 Chrome 中使用 iframe 的 onload 事件。这个answer 可以让您了解如何解决它。

【讨论】:

  • 长话短说,Chrome 中的下载不会调用 readystatechangeonload 事件处理程序。
  • 请参考以下帖子获取示例代码:stackoverflow.com/questions/12076494/...。我花了一些时间才弄清楚其他地方的许多其他答案,它们指的是 onload 事件的使用,实际上是错误的。这可能与最新的网络浏览器更符合规范有关。
【解决方案2】:

你可以用另一种方式来做:

在主文档中:

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

在 iframe 文档中(即在 url 引用的页面的 html 中)

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

如果主页面和 iframe 内的页面在同一个域中,这将起作用。

其实可以通过以下方式访问父级:

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

使用window.parent 更安全,因为变量parenttop 可能会被覆盖(通常不是有意的)。

【讨论】:

    【解决方案3】:

    你必须考虑2点:

    1- 首先,如果您的 url 具有不同的域名,则无法执行此操作,除非您有权访问其他域以添加 Access-Control-Allow-Origin: * 标头,要解决此问题,请转到此 link .

    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
        });
    };
    

    我在各种浏览器中都这样做过。

    【讨论】:

      【解决方案4】:

      我刚刚注意到 Chrome 并不总是触发主页的加载事件,因此这也可能对 iframe 产生影响,因为它们的处理方式基本相同。

      使用开发工具或性能 API 检查加载事件是否被触发。

      我刚刚检查了http://ee.co.uk/,如果您打开控制台并输入 window.performance.timing,您会发现 domComplete、loadEventStart 和 loadEventEnd 的条目为 0 - 至少在当前时间:)

      Chrome 似乎存在问题 - 我已在 2 台使用最新版本 31.0.1650.63 的 PC 上检查过。

      更新:再次检查 ee 并触发了 load 事件,但在随后的重新加载中没有,因此这是间歇性的,可能与他们网站上的加载错误有关。但是加载事件应该触发任何东西。

      由于我注意到我自己的站点监控偶尔会失败,因此在最后一天我已经在 5 或 6 个站点上发生了此问题。只是查明了原因。我需要睡个美容觉,等我清醒一点再进一步调查。

      【讨论】:

        【解决方案5】:

        我讨厌这个,但除了定期检查之外,我找不到任何其他方法,只能检查它是否仍在加载。

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

        【讨论】:

        • 这应该是直接下载的公认答案。我要添加的唯一部分是最大时间,因此它不会永远等待。
        • 这不起作用。甚至在服务器开始发送响应之前,iframeDoc.readyState 就设置为已完成。
        【解决方案6】:

        我遇到了 iframe 加载时间过长的问题。在未处理请求时注册为已加载的 iframe。我想出了以下解决方案:

        JS

        功能:

        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)
        }
        

        用法:

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

        jQuery

        功能:

        $.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)
        }
        

        用法:

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

        【讨论】:

          猜你喜欢
          • 2015-05-20
          • 1970-01-01
          • 1970-01-01
          • 2013-11-23
          • 1970-01-01
          • 2011-10-28
          • 2016-10-27
          • 1970-01-01
          • 2020-03-27
          相关资源
          最近更新 更多