模态对话框导致setTimeout失效的解决方案(一)

web开发中,大家有可能经历过下面这种问题:
① 画面上通过setTimeout启动了一个定时器,用以动态更新画面上的某个组件(比如,1 秒刷新一次时间中的秒数)
② 当页面弹出一个模态对话框(通过 showModalDialog打开)时候,你会发现画面上的setTimeout失效了(比如,时间不再是一秒刷新一次了)

发生这个问题的原因大家可能都知道:模态对话框的特性导致了这个问题。在关闭模态对话框之前,用户无法将父窗口进行任何操作。而且Javascript又是单线程的,导致在模态对话框打开之后,被启动的setTimeout定时器,即时到了指定时间之后,也没有机会被执行。

那么,如果解决这个问题呢?
目前,我共找到两个解决方案,本篇blog中先描述方案一。下面开始。

方案一是采用 iframe 来实现的。
模态对话框导致setTimeout失效的解决方案(一)_第1张图片
 该方案的大体思路如下:

① 新建一个主HTML文件,如上面的index.html,该文件仅仅用于存放两个iframe,代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>setTimeout无效的解决方案(一)</title>
</head>
<body>
    <!-- 这个iframe用来显示画面内容 -->
    <div id="frameDiv1">
       <iframe id="dlgFrame1" name="dlgFrame1" src="frame1.html" style="width: 100%; height: 100%; border: none;"></iframe>
    </div>
    
    <!-- 这个iframe仅仅用于打开模态对话框,所以将其隐藏 -->
    <div id="frameDiv2" style="display: none;">
       <iframe id="dlgFrame2" name="dlgFrame2" src="frame2.html"></iframe>
    </div>
</body>
</html>

 

 ② 新建一个iframe,如上面的iframe1.html,此文件用来展示你想在画面上显示的东西,代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script>
    function start() {
        (event.target || event.srcElement)["disabled"] = true;
        setTimeout(function(){
            document.querySelector("#txt").innerText = Math.random();
            setTimeout(arguments.callee, 1000);
        }, 1000);
    }
    
    function dlgOpenButton() {
        // 获取iframe2的window对象,通过此window对象打开模态对话框
        document.querySelector("#txt2").innerText = "模态画面打开中。。。";
        var win = window.top.document.querySelector("#dlgFrame2").contentWindow;
        var val = win.showModalDialog("dialog.html",Math.random());
        document.querySelector("#txt2").innerText = "模态画面关闭了,返回值为: " + val;
        
        // 如果是通过alert来打开的话,仍然是不行的。这个目前还无解。
        //var val = win.alert("modal dialog");
        //document.querySelector("#txt2").innerText = "模态画面关闭了,返回值为: " + val;
    }
</script>
</head>
<body>
    <button type="button" onclick="start()">启动定时器</button>
    <button type="button" onclick="dlgOpenButton()">打开模态对话框</button>
    <div>
        <p style="float: left;">定时更新内容:</p>
        <p id="txt" style="float: left;"></p>
    </div>
    <div style="float: left; clear: left;">
        <p style="float: left;">模态对话框状态:</p>
        <p id="txt2"></p>
    </div>
</body>
</html>

 ③ 新建另一个iframe,如上面的iframe2.html,此文件仅仅用于打开模态对话框,代码如下:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
</body>
</html>

 ④ 最后,要打开的模态对话框的代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>我是模态对话框</title>
<script>
    window.onload = function() {
        var para = window.dialogArguments;
        document.querySelector("#fromParent").innerText = para;
    };
    
    window.onunload = function() {
        window.returnValue = Math.random();  
    };
</script>
</head>
<body>
    <div>
        <p>我是模态对话框,父画面传给我的值是: </p>
        <p id="fromParent"></p>
    </div>
    <br/>
</body>
</html>

 

上面将相关代码添完了,下面简单说一下此方案的思路:首先,我们是准备在iframe1里启动定时器的,所以,我们为了不让iframe1中的定时器失效,我们就不能再在iframe1中打开模态对话框,理由在上面已经描述过了。这样一来,我们只能寻找另外一种方案,使得能够打开模态对话框,同时又不阻断iframe1中的定时器。这样想的话,我们只好借用一下其他window对象,并调用其showModalDialog方法来打开模态对话框。所以,iframe2就派上用场了。即,在iframe1中,获取到iframe2的window对象,然后打开模态对话框,这种方式打开的模态对话框是不会阻断iframe1中的setTiemout的。

 

大家可以打开附件iframe.zip,然后运行其中的 index.html,如下图。然后先点击“启动定时器”按钮,然后再点击“打开模态对话框”按钮,观察一下画面,便可验证。


模态对话框导致setTimeout失效的解决方案(一)_第2张图片 

 

PS:

① 以上方案仅在IE10中进行过了验证。
 ② 对于alert之类的对话框上述方案无效。

你可能感兴趣的:(JavaScript,iframe,showModalDialog,settimeout,失效)