returnValue of Chrome


說實話,我一看到這個returnValue就有點反感,感覺這個就是IE式的老套的用法,因為項目中有用到就了解了下,以下主要是一些我的理解和發現吧。

PS:returnValuewindow的屬性,showModalDialogopenwindow的方法。

returnValue是與showModalDialog搭配使用的,showModalDialog用於打開窗口,與open類似效果,但通過showModalDialog打開窗口時有如下特點:

  1. 打開窗口后,將不能再操作父窗口了(正常情況下,父窗口將獲取不到焦點了);
  2. 確切的說父窗口在執行showModalDialog這一步時停止了,等待子窗口操作返回,而showModalDialog之后的js代碼也就暫時不會執行了;
  3. returnValue就是返回值,子窗口通過window.returnValue將操作結果返回給父窗口,在子窗口調用window.close方法后,returnValue將作為showModalDialog的返回值傳遞到父窗口中,之后繼續執行showModalDialog后面的js代碼;

網上的搜羅了下,都說IE、Firefox支持的,而Chrome雖然有showModalDialog方法,但效果僅僅類似open,且不支持returnValue,至於Opera則完全不支持(應該說的不是Webkit內核的Opera)。

初步寫代碼測試了下(只測IE、Firefox、Chrome),我寫了三個頁面,主要邏輯是:t1中打開t2、t2中打開t3、同時每個頁面上添加點擊測試、刷新測試按鈕(用於Chrome測試),基本html代碼如下,可直接點擊頁面地址進行瀏覽:

t1.html代碼:
<!doctype html>
<html>
    <meta charset="utf-8"/>
    <title>t1</title>
    <script>
        alert("load t1");
        function openT2(){
            alert(showModalDialog('t2.html',{msg:"arguments from t1.html",win:window},''));
            alert('子窗口已關閉');
        }
        function openT1Self(){
            alert(showModalDialog('t1.html',{msg:"arguments from t1.html",win:window},''));
            alert('子窗口已關閉');
        }
        function closeSelf(){
            window.returnValue='從t1正常返回的returnValue';
            window.close();
        }
        if(window.dialogArguments){
            if(window.dialogArguments.msg){
                alert(window.dialogArguments.msg);
            }else{
                alert(window.dialogArguments);
            }
        }
        function reloadPage(){
            alert('before');
            window.location.reload();
            alert('after');
        }
        function setReturnValue(){
            var str = prompt("請輸入returnValue值")
            window.returnValue = "t1在刷新前所賦的returnValue:"+str;
            alert("賦值完畢,請點擊刷新!");
        }
    </script>
    <body>
        <a href="javascript:openT2();">打開t2</a>
        <a href="javascript:openT1Self();">打開t1自己</a>
        <a href="javascript:closeSelf();">關閉</a>
        <a href="javascript:alert('點擊了');">Chrome下點擊測試</a>
        <a href="javascript:setReturnValue();">在刷新前給returnValue賦值</a>
        <a href="javascript:reloadPage();">點擊刷新</a>
    </body>
</html>
t2.html代碼:

 

<!doctype html>
<html>
    <meta charset="utf-8"/>
    <title>t2</title>
    <script>
        alert("load t2");
        function openT3(){
            alert(showModalDialog('t3.html',{msg:"arguments from t2.html",win:window},''));
            alert('子窗口已關閉');
        }
        function closeSelf(){
            window.returnValue='從t2正常返回的returnValue';
            window.close();
        }
        if(window.dialogArguments){
            if(window.dialogArguments.msg){
                alert(window.dialogArguments.msg);
            }else{
                alert(window.dialogArguments);
            }
        }
        function reloadPage(){
            alert('before');
            window.location.reload();
            alert('after');
        }
        function setReturnValue(){
            var str = prompt("請輸入returnValue值")
            window.returnValue = "t2在刷新前所賦的returnValue:"+str;
            alert("賦值完畢,請點擊刷新!");
        }
    </script>
    <body>
        <a href="javascript:openT3();">打開t3</a>
        <a href="javascript:closeSelf();">關閉</a>
        <a href="javascript:alert('點擊了');">Chrome下點擊測試</a>
        <a href="javascript:setReturnValue();">在刷新前給returnValue賦值</a>
        <a href="javascript:reloadPage();">點擊刷新</a>
    </body>
</html>
t3.html代碼:

 

<!doctype html>
<html>
    <meta charset="utf-8"/>
    <title>t3</title>
    <script>
        alert("load t3");
        function closeSelf(){
            window.returnValue='從t3正常返回的returnValue';
            window.close();
        }
        if(window.dialogArguments){
            if(window.dialogArguments.msg){
                alert(window.dialogArguments.msg);
            }else{
                alert(window.dialogArguments);
            }
        }
        function reloadPage(){
            alert('before');
            window.location.reload();
            alert('after');
        }
        function setReturnValue(){
            var str = prompt("請輸入returnValue值")
            window.returnValue = "t3在刷新前所賦的returnValue:"+str;
            alert("賦值完畢,請點擊刷新!");
        }
    </script>
    <body>
        <a href="javascript:closeSelf();">關閉</a>
        <a href="javascript:setReturnValue();">在刷新前給returnValue賦值</a>
        <a href="javascript:reloadPage();">點擊刷新</a>
    </body>
</html>
測試1

直接將t1.html文件拖入瀏覽器瀏覽進行測試。

測試結果:
  • IE、Firefox沒有問題;
  • Chrome下則returnValue幾乎無效,具體細節:

    1. showModalDialog效果接近open,即只是打開了一個新窗口而已,父窗口仍然可以操作,而showModalDialog后的語句沒有執行,但控制台上卻有些信息提示,有一個警告(灰色)和錯誤(紅色):

      Chromium is considering deprecating showModalDialog. Please use window.open and postMessage instead.

      Uncaught SecurityError: Blocked a frame with origin "null" from accessing a frame with origin "null". Protocols, domains, and ports must match.

      警告信息表明Chromium將棄用showModalDialog(經驗證,在Chromium38.0.2074.0中,showModalDialog已報undefined錯誤,看來已被遺棄,見官方Issue345831,不知Chrome之后會不會如此……)。

      錯誤信息是在關閉子窗口后出來的,這個就是說明了為什么returnValue無效以及showModalDialog后面的語句為什么沒執行(報錯了么,呵呵),這個錯誤似乎跟跨域訪問有點類似啊。

      PS:在較老版本的Chrome中並不會有這里的警告及錯誤信息,故可能讓人誤以為不支持returnValue

      PPS@2014/09/14: 最近無意間在Firefox(版本號是32)的控制台也看到類似的提示信息,如下所示,看來ShowModalDialog的結局可想而知了。

      window.showModalDialog() 已廢棄。請使用 window.open() 代替。更多信息見 https://developer.mozilla.org/en-US/docs/Web/API/Window.open

    2. 當t1.html通過showModalDialog打開t1.html(即自己)的時候,returnValue竟起作用了,但在子窗口打開的情況下父窗口仍然可以操作,不同的是的showModalDialog后面的語句在關閉子窗口后執行了,說明此時沒有1中的那個錯誤了;

    3. 但如果子頁面刷新了,則無論之后給returnValue賦什么值,最終showModalDialog的返回值將一直是子頁面第一次刷新前給returnValue所賦的值,如果第一次刷新前沒有給returnValue賦值,則將是undefined,這說明子頁面在刷新后與父頁面失去了聯系,導致returnValue失效;

    4. 在子窗口打開情況下,雖然父窗口能夠操作,但在父窗口中點擊“點擊刷新”后兩個alert都執行了,而頁面卻沒有刷新,說明有些特殊操作如window.location.reload();將會等到子窗口關閉后才會執行。

通過測試1得知在chrome下本地直接瀏覽網頁的形式使用showModalDialog存在類似跨域訪問的錯誤,因此需要將網頁放到Web應用服務器上測試,至於子頁面刷新導致的問題也許就那樣了,算是個bug吧。

測試2

將三個頁面放到Web應用服務器(Tomcat)上,然后打開t1.html瀏覽進行測試。

測試結果:
  • IE、Firefox沒有問題;
  • Chrome下則returnValue基本有效,具體細節:
    1. 正常操作情況下,能夠通過returnValue返回數據,showModalDialog后面的代碼也能在關閉子窗口后執行;
    2. 但如果子頁面刷新了,則無論之后給returnValue賦什么值,最終showModalDialog的返回值將一直是子頁面第一次刷新前給returnValue所賦的值,如果第一次刷新前沒有給returnValue賦值,則將是undefined,這說明子頁面在刷新后與父頁面失去了聯系,導致returnValue失效;
    3. 在子窗口打開情況下,雖然父窗口能夠操作,但在父窗口中點擊“點擊刷新”后兩個alert都執行了,而頁面卻沒有刷新,說明有些特殊操作如window.location.reload();將會等到子窗口關閉后才會執行。

總結

鑒於網上發表的關於Chrome之returnValue的文章都是幾年前的,也許那時確實是完全不支持returnValue吧,不過我拿了個較老的版本(v11)測過,結果大致跟新版一樣。

但Chrome雖然支持returnValue,但使用體驗卻不怎么樣,有以下幾點:

  1. 打開子窗口情況下,還是能夠操作父窗口;
  2. 子窗口在刷新后,returnValue就失效了(window.dialogArguments也變為undefined了),只能返回第一次刷新前的returnValue(該問題可通window.opener傳參解決,該屬性指向父窗口,且不會因為刷新導致失效,具體請參考ref1文中的“解決returnValue問題”小節)

於是乎可以說Chrome不支持returnValue吧,在之后的版本中showModalDialog這個方法應該會被移除了,所以說這個沒有什么意義了啊。

如果一定要繼續用showModalDialog的話,可以考慮在子窗口中通過window.opener與父窗口進行傳參來代替returnValue的方式,而用open來代替showModalDialog,而在子窗口打開情況下,可以在父窗口中覆蓋一層div來禁用用戶操作等等,還是可以將就着模擬showModalDialog的效果的,但要完全模擬,有點困難啊。

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM