說實話,我一看到這個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中並不會有這里的警告及錯誤信息,故可能讓人誤以為不支持
returnValue
PPS@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
的效果的,但要完全模擬,有點困難啊。