頁面關閉彈出提示并注銷登錄(兼容主流瀏覽器)
這是多么普遍而又正常的需求啊,然而在多瀏覽器時代,這又是多么難做啊~~(我不是FE,我是Java工程師)
目前這個代碼能夠兼容以下瀏覽器(我親測過的):
IE8,Chrome12,Firefox5,Safari4
應該也能支持以下瀏覽器:
IE7,Chrome8以后的版本,Firefox3.6,4
由于我們的系統不支持IE6,因此就不考慮這個問題了,估計應該沒啥問題。
由于Opera不支持beforeunload事件,因此不會彈出提示讓用戶決定是否退出,同時對于刷新回退等操作也不會調用unlaod,因為它認為那是reload,會直接從cache中獲得。我唯一成功響應Opera的unload事件是將Opera關閉了,然后再打開由于它會保留上次的標簽,因此會重新加載,就在這個時候它響應了unload。因此放棄對Opera的支持,畢竟我們的服務對象沒什么人用。
本來的邏輯是當用戶關閉或者刷新或者后退時會彈出一個提示框詢問用戶是否真的關閉,這里面有以下幾個技術陷阱:
1 這個事情只能通過beforeunload完成,但是一旦注冊了這個事件,瀏覽器就會彈出個確認框,不需要你自己寫什么confirm,我起初不知道,因為使用了一個開源的產品,找遍了它所有的代碼想解除綁定或者屏蔽那個確認框,后來才發現原來是瀏覽器內置的!
其用法如下:
- window.onbeforeunload=function(){
- return 'Are you really going to leave?';
- }
注意這個地方IE,Firefox,Chrome,各不相同,Safari跟IE相同:
IE和Safari會顯示一段內置的話,然后中間顯示你這句話;
Firefox只會顯示它內置的提示;
Chrome只會顯示你寫的這段話。
后面讓人崩潰的瀏覽器差異還有很多。
2 當刷新或后退時,執行的流程是beforeunload事件,unload事件和load事件。
但是IE會彈出兩次那個提示框。
3 當unload事件觸發時,退出登錄,有兩種方法:
1)發送Ajax請求退出
2)location.href
但是,Chrome和Safari(這倆瀏覽器是一個內核)在unload方法里執行location.href無效。
按照網上說的各種方法,比如window.location,self.location,navigate.go(0)等等,都無效。
然后使用window.close替代,也無效,后來發現可以這樣:
window.open('', '_self', ''); //bug fix
window.close();
這樣搞完又會彈兩次框。這很正常,因為又打開了一個窗口嘛。
4 Chrome執行完unload事件后,因為沒有執行location.href因此繼續執行onload方法,悲劇發生了,雖然注銷登錄成功了(通過Ajax的方式),但是本頁面并沒有被filter攔截跳轉到登錄頁面,但是其中引入的js,iframe卻被filter攔住了,通過Fiddler2觀察確實發送了很多次Login那個頁面的請求,然后頁面由于該加載的JS沒過來,就在那兒不動了。這時只有點擊刷新,才會真正的跳轉到Login頁面。
這是使用window.close的一個理由,否則就算location.href不成功,能在onload時自動跳轉也沒事,但可惜不行。
5 IE和Chrome彈兩次這個問題,應該是通過將綁定事件放到onload,而不是直接寫在<script>標簽中。可能是這兩個瀏覽器的某種機制使得他們會執行兩次。
全部代碼如下:
<script language='javascript'>
- function getOs(){
- if(navigator.userAgent.indexOf("MSIE")>0)return 1;//IE
- if(isFirefox=navigator.userAgent.indexOf("Firefox")>0)return 2;//Firefox
- if(isSafari=navigator.userAgent.indexOf("Chrome")>0)return 3;//Chrome
- if(isSafari=navigator.userAgent.indexOf("Safari")>0)return 4;//Safari
- if(isCamino=navigator.userAgent.indexOf("Camino")>0)return 5;//Camino
- if(isMozilla=navigator.userAgent.indexOf("Gecko/")>0)return 6;//Gecko
- if(isOpera=navigator.userAgent.indexOf('Opera') >= 0) return 7;//Opera
- //other...
- return 0;
- }
- var quite=false;
- function bindOnbeforeunload(){
- quite=false;
- window.onbeforeunload=checkLeave;
- }
- function unbindOnbeforeunload(){
- quite=true;
- window.onbeforeunload=null;
- }
- function checkLeave(){
- return '您正在離開...';
- }
- window.onunload=function(){
- try{
- unbindOnbeforeunload();
- }catch(e){
- }
- window.location.href='/Logout';
- if(getOs()==3||getOs()==4){
- var xmlHttp = false;
- try {
- xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
- } catch (e) {
- try {
- xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
- } catch (e2) {
- xmlHttp = false;
- }
- }
- if (!xmlHttp && typeof XMLHttpRequest != 'undefined') {
- xmlHttp = new XMLHttpRequest();
- }
- var url = "/Logout";
- xmlHttp.open("POST", url, false);
- // Send the request
- xmlHttp.send(null);
- window.open('', '_self', ''); //bug fix
- window.close();
- }
- }
- </script>
- </head>
在HTML body中注冊:
<body oncontextmenu="return false;" onload="javascript:return bindOnbeforeunload();" >
posted on 2011-08-02 13:24 零雨其蒙 閱讀(5751) 評論(1) 編輯 收藏 所屬分類: 前端開發