欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-06 14:18:16
...

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

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

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

方案一是采用 iframe 来实现的。
模态对话框导致setTimeout失效的解决方案(一)
            
    
    博客分类: JavaScript JavaScriptsetTimeoutshowModalDialog失效iframe 
 该方案的大体思路如下:

① 新建一个主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失效的解决方案(一)
            
    
    博客分类: JavaScript JavaScriptsetTimeoutshowModalDialog失效iframe  

 

PS:

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

  • 模态对话框导致setTimeout失效的解决方案(一)
            
    
    博客分类: JavaScript JavaScriptsetTimeoutshowModalDialog失效iframe 
  • 大小: 25.5 KB
  • 模态对话框导致setTimeout失效的解决方案(一)
            
    
    博客分类: JavaScript JavaScriptsetTimeoutshowModalDialog失效iframe 
  • 大小: 2.9 KB