检测当一个iframe开始加载新的URL。

52

如何检测页面中的 iframe 开始加载新页面?

我们的情况是:

  • 当 iFrame 内容开始更改时,我们需要显示“加载”动画并隐藏搜索框。
  • 我知道如何处理“iframe 已经完成加载”的事件(以隐藏动画),但不知道如何捕获最初的“开始更改”的事件...

注意: 我可以将 jquery 的“click”钩子附加到菜单上的链接上,这样做会起作用。但是,在 iframe 内容内部有许多交叉引用链接,而“更改”事件也适用于它们!因此,我们需要捕获以下事件:当用户在 iframe 内部点击链接或者当 iframe src 通过 JavaScript 更改时 - 因为我们还想显示加载动画并隐藏搜索框。


也许这可以帮助:http://stackoverflow.com/a/4010296/1427878 - CBroe
可能是 iFrame src change event detection? 的重复问题。 - T.Todua
4个回答

37

如果iframe和容器页面同域,我发现了一种更好的解决方案,不需要在内部页面中添加额外的代码:

<iframe src="same-origin.com" onload="content_finished_loading(this)"></iframe>
<script>
    var indicator = document.querySelector('.loading-indicator');
    var content_start_loading = function() {
        indicator.style.display = 'block';
    };

    var content_finished_loading = function(iframe) {
        indicator.style.display = 'none';
        // inject the start loading handler when content finished loading
        iframe.contentWindow.onunload = content_start_loading;
    };
</script>

1
哇,非常令人印象深刻的解决方案 :) 我喜欢它! - Philipp
1
完美!好主意! - Tejasvi Hegde
正如@jbyrd在下面的评论中提到的那样,使用iframe.contentWindow.onbeforeunload而不是.onunload将更早地触发回调,事实上就在发送新请求时。 - Lionel
请注意,仅当 iframe contentWindow 与尝试设置事件侦听器的脚本具有相同的来源时,此方法才有效。 - bodo

29
我想到了以下解决方案-这只有在我们控制iframe内容和主窗口的情况下才可能实现。
在iframe内部,我们将以下脚本添加到页面页脚(所有页面都使用相同的模板,因此这是对单个文件的更改)。
<script>
window.onunload = function() {
    // Notify top window of the unload event
    window.top.postMessage('iframe_change', '*');
};
</script>

在主窗口内,我们添加了这个脚本来监控iframe的状态。

function init_content_monitor() {
    var content = jQuery('.iframe');

    // The user did navigate away from the currently displayed iframe page. Show an animation
    var content_start_loading = function() {
        alert ('NOW: show the animation');
    }

    // the iframe is done loading a new page. Hide the animation again
    var content_finished_loading = function() {
        alert ('DONE: hide the animation');
    }

    // Listen to messages sent from the content iframe
    var receiveMessage = function receiveMessage(e){
        var url = window.location.href,
            url_parts = url.split("/"),
            allowed = url_parts[0] + "//" + url_parts[2];

        // Only react to messages from same domain as current document
        if (e.origin !== allowed) return;
        // Handle the message
        switch (e.data) {
            case 'iframe_change': content_start_loading(); break;
        }
    };
    window.addEventListener("message", receiveMessage, false);

    // This will be triggered when the iframe is completely loaded
    content.on('load', content_finished_loading);
}

1
不错的解决方案,它帮了我很大忙。我将window.onunload语句更改为以下内容:$(window).on('beforeunload ',function() { window.top.postMessage('iframe_change', '*'); }); 这对我来说速度更快。 - Breixo
1
在我看来,这过于复杂了,并且忽略了关键事件应该是 onbeforeunload 而不是 onunload 的主要观点。原帖明确说明了他想知道一个框架何时开始加载新的 URL。请参见 https://dev59.com/l10a5IYBdhLWcg3wF1UL#30719095。 - jbyrd
如果我加载的URL(在iFrame中)来自不同的域,这个会起作用吗? - Yugandhar Pathi
@YugandharPathi 是的。请注意postMessage方法的第二个参数是“*”,这意味着消息会发布到顶层窗口上下文,无论它托管在哪个域中。所以该iframe可以托管在任何其他地方。 - Alisson Reinaldo Silva
顺便说一下,非常好的解决方案。这对我帮助很大,我也需要知道iframe何时开始加载新的URL,而这个方法完美地适用于我的特定情况。 - Alisson Reinaldo Silva

0

已经有可能的解决方案在这里: iFrame src change event detection?

然而,如果您想操作目标页面,那么无需触及 iframe-target 文件内容。只需在父页面中添加正确的 JS 代码即可访问相同源 iframe。我用的是类似这样的代码:

<iframe id="xyz" ....>
.....
<script>
var iframeElement = document.getElementById("xyz");
var iframe_El = iframeElement.contentDocument || iframeElement.contentWindow.document;
// manipulate iframe_El wih "on complete" events and like that.
....
</script>

更多内容请参见:https://jsfiddle.net/Lnb1stc8/


-1
当您动态创建iframe时,请包含ONLOAD事件,如下所示...
F=document.createElement('iframe');
F.onload=function(){
    UpdateDetails(
        this.contentWindow.document.title,
        this.contentWindow.location
    );
};
F.src='some url';
document.getElementById('Some_Container').appendChild(F);

当用户浏览网页时,onload事件将通过下面的函数不断更新以下全局变量:

var The_Latest_Title='';
var The_Latest_URL='';
function UpdateDetails(Title,URL){
    The_Latest_Title=Title;
    The_Latest_URL=URL;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接