[Javascript] 將window.showModalDialog改成window.open

using window.open instead of  window.showModalDialog

前言

在最近維護舊專案中,發現到處都有使用Javascript的window.showModalDialog來另開視窗給user操作

但是在Chrome、Filefox等瀏覽器已不再支援window.showModalDialog,只剩風中殘燭的IE支援它

大概在以前的時代,開發人員沒想到當時主流的IE到了今天會沒落,所以寫了window.showModalDialog這種只有IE支援的Javascript語法

實作

想把window.showModalDialog改寫成window.open前,得先瞭解兩者的輸入、回傳參數

Window.showModalDialog() MDN

↑劃紅線的地方為值得留意在window.open中無法使用的參數

1.在window.showModalDialog中,可以透過第二個參數,傳遞任何Javascript的值給子視窗,包含字串、數字、JS物件、陣列、DOM元素....

然後在子視窗透過window.dialogArguments即可取得父視窗傳遞的值。

2.在window.showModalDialog裡的子視窗關閉後,父視窗可以透過上述的returnVal(一個變數) 來接收子視窗的回傳值(可能是字串、JS物件、DOM元素等等)

但換成呼叫window.open,returnVal則變成回傳子視窗window物件(但IE會返回undefined)

window.open MDN

先看window.showModalDialog範例寫法↓

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="A.aspx.cs" Inherits="WebApplication1showmodal.A" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>父視窗 </title>
</head>
<body>
    <form id="form1" runat="server"> 
        <input type="button" value="另開視窗" id="btnParent" />

        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

        <script type="text/javascript">
           
            $(function () {
                $("#btnParent").on("click", function () {
                    let parentParam = "我是老爸";//父視窗要傳給子視窗的值
                    let ret = window.showModalDialog("B.aspx", parentParam, "dialogWidth=500px;dialogHeight=500px");

                    alert("子視窗回傳值:" + ret);
                });
            });
        </script>
    </form>
</body>
</html>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="B.aspx.cs" Inherits="WebApplication1showmodal.B" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>子視窗</title>
</head>
<body>
    <form id="form1" runat="server">

        <input type="button" value="關閉子視窗" id="btnSub" />
        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script type="text/javascript">
            $(function () {
                //取得父視窗傳遞的值
                let parentParam = window.dialogArguments;
                alert(parentParam);
                $("#btnSub").on("click", function () {

                    window.returnValue = "我是子視窗的回傳值";
                    window.close();
                });
            });
        </script>
    </form>
</body>
</html>

或把父視窗的DOM元素傳給子視窗,讓子視窗操作↓

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="A.aspx.cs" Inherits="WebApplication1showmodal.A" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>父視窗 </title>
</head>
<body>
    <form id="form1" runat="server"> 
        <input type="button" value="另開視窗" id="btnParent" />
        <!--父視窗的DOM元素-->
        <div id="divParent"></div>


        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

        <script type="text/javascript">
           
            $(function () {
                $("#btnParent").on("click", function () {
                    let ret = window.showModalDialog("B.aspx", document.getElementById("divParent"), "dialogWidth=500px;dialogHeight=500px");

                    alert("子視窗回傳值:" + ret);
                });
            });
        </script>
    </form>
</body>
</html>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="B.aspx.cs" Inherits="WebApplication1showmodal.B" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>子視窗</title>
</head>
<body>
    <form id="form1" runat="server">

        <input type="button" value="關閉子視窗" id="btnSub" />
        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script type="text/javascript">
            $(function () {
                //取得父視窗傳遞的DOM元素
                let divParentDom = window.dialogArguments;
                divParentDom.innerHTML = "被子視窗操作了~";
                $("#btnSub").on("click", function () { 
                    window.returnValue = "我是子視窗的回傳值";
                    window.close();//關閉子視窗
                });
            });
        </script>
    </form>
</body>
</html>

再來看改寫成window.open的幾種方式↓

1.從子視窗(B.aspx)回傳值給父視窗(A.aspx)

在子視窗透過window.opener來存取父視窗並給予值

↓子視窗操作父視窗DOM元素範例

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="A.aspx.cs" Inherits="WebApplication1showmodal.A" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>父視窗 </title>
</head>
<body>
    <form id="form1" runat="server"> 
        <input type="button" value="另開視窗" id="btnParent" />
         <!--父視窗的DOM元素-->
        <div id="divParent"></div>

        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script type="text/javascript">
            $(function () {
                $("#btnParent").on("click", function () {
                    //另開popup window
                    window.open("B.aspx", "_blank", "width=500px,height=500px,scrollbars=1");//scrollbars=1,給IE看的
                   
                });
            });
        </script>
    </form>
</body>
</html>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="B.aspx.cs" Inherits="WebApplication1showmodal.B" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>子視窗</title>
</head>
<body>
    <form id="form1" runat="server">

        <input type="button" value="關閉子視窗" id="btnSub" />
        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script type="text/javascript">
            $(function () { 
                $("#btnSub").on("click", function () {  
                    //操作父視窗的DOM元素 
                    window.opener.document.getElementById("divParent").innerHTML = "兒子給的值";
                    window.close();//關閉子視窗
                });
            });
        </script>
    </form>
</body>
</html>

↓子視窗把值傳給父視窗的function去執行

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="A.aspx.cs" Inherits="WebApplication1showmodal.A" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>父視窗 </title>
</head>
<body>
    <form id="form1" runat="server"> 
        <input type="button" value="另開視窗" id="btnParent" />
         
        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script type="text/javascript">
            $(function () {
                $("#btnParent").on("click", function () {
                    //另開popup window
                    window.open("B.aspx", "_blank", "width=500px,height=500px,scrollbars=1");//scrollbars=1給IE看的
                   
                });
            });

            //注意父視窗要宣告成global function
            function windowOpenReturnFunc(ret) {
                //ret為子視窗回傳的值
                alert("子視窗回傳的值:"+ret);
            }
        </script>
    </form>
</body>
</html>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="B.aspx.cs" Inherits="WebApplication1showmodal.B" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>子視窗</title>
</head>
<body>
    <form id="form1" runat="server">

        <input type="button" value="關閉子視窗" id="btnSub" />
        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script type="text/javascript">
            $(function () { 
                $("#btnSub").on("click", function () {   
                    let subParam = "兒子的值";
                    window.opener.windowOpenReturnFunc(subParam);//執行父視窗的function
                    window.close();//關閉子視窗
                });
            });
        </script>
    </form>
</body>
</html>

2.從父視窗(A.aspx)傳值給子視窗(B.aspx)

雖然有人提出使用QueryString來實作,但我覺得QueryString是給Server端讀取,就不介紹此種辦法XD

有興趣的人自行看文章:window.open()改写showModalDialog()参数传递总结

第一種方法:子視窗透過window.opener來取得父視窗的值

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="A.aspx.cs" Inherits="WebApplication1showmodal.A" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>父視窗 </title>
</head>
<body>
    <form id="form1" runat="server"> 
        <input type="button" value="另開視窗" id="btnParent" />
         
        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

        <script type="text/javascript">
            //注意要用var宣告變數並且放在global區域,才會變成window的屬性
            var parentParam = "我是老爸";
            $(function () {
                $("#btnParent").on("click", function () {
                    //另開popup window
                    window.open("B.aspx", "_blank", "width=500px,height=500px,scrollbars=1");//scrollbars=1給IE看的
                      
                });
            });
        </script>
    </form>
</body>
</html>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="B.aspx.cs" Inherits="WebApplication1showmodal.B" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>子視窗</title>
</head>
<body>
    <form id="form1" runat="server">

        <input type="button" value="關閉子視窗" id="btnSub" />
        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script type="text/javascript">
            $(function () {
                //取得父視窗傳遞的值
                alert(window.opener.parentParam);
                $("#btnSub").on("click", function () {  
                    window.close();//關閉子視窗
                });
            });
        </script>
    </form>
</body>
</html>

父視窗要傳遞DOM元素給子視窗的情況↓

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="A.aspx.cs" Inherits="WebApplication1showmodal.A" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>父視窗 </title>
</head>
<body>
    <form id="form1" runat="server"> 
        <input type="button" value="另開視窗" id="btnParent" />
        <!--父視窗的DOM元素-->
        <div id="divParent"></div>
         
        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

        <script type="text/javascript">
            $(function () {
                $("#btnParent").on("click", function () {
                    //另開popup window
                    window.open("B.aspx", "_blank", "width=500px,height=500px,scrollbars=1");//scrollbars=1給IE看的
                      
                });
            });
        </script>
    </form>
</body>
</html>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="B.aspx.cs" Inherits="WebApplication1showmodal.B" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>子視窗</title>
</head>
<body>
    <form id="form1" runat="server">

        <input type="button" value="關閉子視窗" id="btnSub" />
        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script type="text/javascript">
            $(function () {
                //取得父視窗的DOM
                window.opener.document.getElementById("divParent").innerHTML = "被子視窗操作了~"
                $("#btnSub").on("click", function () {  
                    window.close();//關閉子視窗
                });
            });
        </script>
    </form>
</body>
</html>

第二種:父視窗呼叫window.open後會馬上回傳一個子視窗物件,父視窗再對那個子視窗物件寫值,即可讓子視窗讀得到值

※不過此種方法在IE反而回傳undefined,所以不推

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="A.aspx.cs" Inherits="WebApplication1showmodal.A" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>父視窗 </title>
</head>
<body>
    <form id="form1" runat="server"> 
        <input type="button" value="另開視窗" id="btnParent" />
          
        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

        <script type="text/javascript">
            $(function () {
                $("#btnParent").on("click", function () {
                    //另開popup window
                    let subWindow = window.open("B.aspx", "_blank", "width=500px,height=500px,scrollbars=1");//scrollbars=1給IE看的
                    subWindow.myParam = "從老爸給的值";
                      
                });
            });
        </script>
    </form>
</body>
</html>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="B.aspx.cs" Inherits="WebApplication1showmodal.B" %>

<!DOCTYPE html>

<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>子視窗</title>
</head>
<body>
    <form id="form1" runat="server">

        <input type="button" value="關閉子視窗" id="btnSub" />
        <!--引用jQuery-->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script type="text/javascript">
            $(function () {
                //取得父視窗給的值
                alert(window.myParam);
                $("#btnSub").on("click", function () {   
                    window.close();//關閉子視窗
                });
            });
        </script>
    </form>
</body>
</html>

剩下window.showModalDialog的第三個參數options 和 window.open的第三個參數 features

這兩者都是控制子視窗的特性(例如視窗大小、要不要捲軸、工具列、狀態列、選單列要不要出現等等),留意window.showModalDialog使用;分號分隔,window.open使用,逗號分隔

window.showModalDialog使用dialogWidth、dialogHeight,而window.open改使用width、height即可。

其他都大同小異,請自行參考「Window open() Method   from w3schools.com 」

結論

總之在window.open情況下,一切都在子視窗使用window.opener來存取父視窗即可,這樣很好記XD

其他文章:js的window.showModalDialog及window.open用法实例分析