Think in G

Never stop ThinkinG…

网页中跨域iframe避免相互刷新死循环的方法

without comments

{lang: 'zh-CN'}

最近在做的系统,需要与客户的网页集成,因此牵涉到了跨域访问的问题。所以使用了大量的iframe绕过浏览器的安全策略。

由于跨域系统的安全限制,这些iframe之间是不能相互通信的,需要靠onload事件和父窗口进行交互,而iframe的刷新动作则须由父窗口控制。

其中遇到了一个有意思的问题。大致是这样的:页面打开时,用户没有登录系统,所有的iframe加载后处于未登录状态,点击任意一个iframe,系统会弹出登录画面,登录系统后,需要重新加载这些iframe,从而实现登录状态的同步。
如下面2张图所示:

iframe-A触发刷新动作

iframe-B触发刷新动作

于是,我在父窗口中写了这样的jquery脚本:

function refresh() {
    __self = $(this);
    $('iframe.myDomain').each(function(){
        if($(this).attr(id) != __self.attr(id)) {
            url = $(this).attr('src');
            url = url.replace(/\?rand=.*$/, '?rand=' + Math.random());
            $(this).attr('src', url);
        }
    });
}

$('iframe.myDomain').each(function(){
    $(this).bind('load', refresh);
});

每当onload事件发生的时候,refresh函数会被触发,然后就会更新其他的iframe。但是,这样做有个重大的问题!如下图所示,当其他的iframe刷新完成的时候,同样会产生onload事件,此时,refresh再次被触发,又去刷新其他的iframe,产生了连锁反应,整个加载动作陷入了死循环!

iframe相互刷新引发死循环

为了避免这样的死循环,我们需要让接受到刷新指令的iframe在重新加载页面后不向其他iframe再次发送刷新指令,同时又要让其自身做好接受下一个刷新指令的准备。实现的方法很简单,只要稍稍修改我们的js代码即可。

function noRefresh() {
    //不触发任何动作的onload事件处理函数
    //重新绑定事件处理函数,为下一次处理onload事件做准备。
    $(this).unbind('load');
    $(this).bind('load', refresh);
}

function refresh() {
    __self = $(this);
    $('iframe.myDomain').each(function(){
        if($(this).attr('id') != __self.attr('id')) {
            url = $(this).attr('src')
            url = url.replace(/\?rand=.*$/, '?rand=' + Math.random());
            //将待刷新的iframe的onload处理函数重新设置
            //其自身刷新后,调用noRefresh,防止刷新事件死循环
            $(this).unbind('load');
            $(this).bind('load', noRefresh);

            //现在,刷新时就不会引起连锁反应了。
            $(this).attr('src', url);
        }
    });
}

$('iframe.myDomain').each(function(){
    //初始化的时候,关闭所有的onload事件
    $(this).bind('load', noRefresh);
});

OK,问题解决!

分享家:Addthis中国
{lang: 'zh-CN'}

Written by ghawk.gu

August 31st, 2010 at 4:42 pm

Leave a Reply