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

IT技术 javascript google-chrome angularjs iframe
2021-02-21 17:54:26

我试图在我的客户端上显示一个“掩码”,而文件是动态生成的服务器端。似乎推荐的解决方法(因为它不是 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 }

但我在那里也没有任何运气。

想法?

6个回答

不幸的是onload,如果内容是附件,则无法在 Chrome 中使用 iframe 的事件。这个答案可能会让您了解如何解决它。

长话短说,Chrome 中不会调用readystatechangeonload事件处理程序进行下载。
2021-04-18 17:54:26
有关示例代码,请参阅以下帖子:stackoverflow.com/questions/12076494/...。我花了一些时间才弄清楚其他地方的许多其他答案,这些答案涉及 onload 事件的使用,但实际上是错误的。这可能与最新的 Web 浏览器更符合规范有关。
2021-05-07 17:54:26

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

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 已设置为已完成。
2021-04-17 17:54:26
这应该是直接下载的公认答案。我要添加的唯一部分是最大时间,因此它不会永远等待。
2021-05-16 17:54:26

你可以用另一种方式做到这一点:

在主文档中:

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可能会被覆盖(通常不是意)。

你必须考虑2点:

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

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

我已经在各种浏览器中做到了这一点。

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

使用 Dev Tools 或 Performance api 检查是否正在触发 load 事件。

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

看起来这里的 Chrome 有问题 - 我已经使用最新版本 31.0.1650.63 在 2 台 PC 上检查了它。

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

自从我注意到我自己的站点监控偶尔会失败以来,这个问题在最后一天发生在我的 5 或 6 个站点上。只是查明了这个原因。我需要睡个美容觉,等我更清醒的时候再调查。