說實話,我一看到這個returnValue就有點反感,感覺這個就是IE式的老套的用法,因為項目中有用到就了解了下,以下主要是一些我的理解和發現吧。
PS:returnValue是window的屬性,showModalDialog和open是window的方法。
returnValue是與showModalDialog搭配使用的,showModalDialog用於打開窗口,與open類似效果,但通過showModalDialog打開窗口時有如下特點:
- 打開窗口后,將不能再操作父窗口了(正常情況下,父窗口將獲取不到焦點了);
- 確切的說父窗口在執行
showModalDialog這一步時停止了,等待子窗口操作返回,而showModalDialog之后的js代碼也就暫時不會執行了; - 而
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幾乎無效,具體細節:-
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中並不會有這里的警告及錯誤信息,故可能讓人誤以為不支持
returnValuePPS@2014/09/14: 最近無意間在Firefox(版本號是32)的控制台也看到類似的提示信息,如下所示,看來
ShowModalDialog的結局可想而知了。window.showModalDialog() 已廢棄。請使用 window.open() 代替。更多信息見 https://developer.mozilla.org/en-US/docs/Web/API/Window.open
-
當t1.html通過
showModalDialog打開t1.html(即自己)的時候,returnValue竟起作用了,但在子窗口打開的情況下父窗口仍然可以操作,不同的是的showModalDialog后面的語句在關閉子窗口后執行了,說明此時沒有1中的那個錯誤了; -
但如果子頁面刷新了,則無論之后給
returnValue賦什么值,最終showModalDialog的返回值將一直是子頁面第一次刷新前給returnValue所賦的值,如果第一次刷新前沒有給returnValue賦值,則將是undefined,這說明子頁面在刷新后與父頁面失去了聯系,導致returnValue失效; -
在子窗口打開情況下,雖然父窗口能夠操作,但在父窗口中點擊“點擊刷新”后兩個
alert都執行了,而頁面卻沒有刷新,說明有些特殊操作如window.location.reload();將會等到子窗口關閉后才會執行。
-
通過測試1得知在chrome下本地直接瀏覽網頁的形式使用showModalDialog存在類似跨域訪問的錯誤,因此需要將網頁放到Web應用服務器上測試,至於子頁面刷新導致的問題也許就那樣了,算是個bug吧。
測試2
將三個頁面放到Web應用服務器(Tomcat)上,然后打開t1.html瀏覽進行測試。
測試結果:
- IE、Firefox沒有問題;
- Chrome下則
returnValue基本有效,具體細節:- 正常操作情況下,能夠通過
returnValue返回數據,showModalDialog后面的代碼也能在關閉子窗口后執行; - 但如果子頁面刷新了,則無論之后給
returnValue賦什么值,最終showModalDialog的返回值將一直是子頁面第一次刷新前給returnValue所賦的值,如果第一次刷新前沒有給returnValue賦值,則將是undefined,這說明子頁面在刷新后與父頁面失去了聯系,導致returnValue失效; - 在子窗口打開情況下,雖然父窗口能夠操作,但在父窗口中點擊“點擊刷新”后兩個
alert都執行了,而頁面卻沒有刷新,說明有些特殊操作如window.location.reload();將會等到子窗口關閉后才會執行。
- 正常操作情況下,能夠通過
總結
鑒於網上發表的關於Chrome之returnValue的文章都是幾年前的,也許那時確實是完全不支持returnValue吧,不過我拿了個較老的版本(v11)測過,結果大致跟新版一樣。
但Chrome雖然支持returnValue,但使用體驗卻不怎么樣,有以下幾點:
- 打開子窗口情況下,還是能夠操作父窗口;
- 子窗口在刷新后,
returnValue就失效了(window.dialogArguments也變為undefined了),只能返回第一次刷新前的returnValue(該問題可通;window.opener傳參解決,該屬性指向父窗口,且不會因為刷新導致失效,具體請參考ref1文中的“解決returnValue問題”小節)
於是乎可以說Chrome不支持returnValue吧,在之后的版本中showModalDialog這個方法應該會被移除了,所以說這個沒有什么意義了啊。
如果一定要繼續用showModalDialog的話,可以考慮在子窗口中通過window.opener與父窗口進行傳參來代替returnValue的方式,而用open來代替showModalDialog,而在子窗口打開情況下,可以在父窗口中覆蓋一層div來禁用用戶操作等等,還是可以將就着模擬showModalDialog的效果的,但要完全模擬,有點困難啊。
