各瀏覽器對 onbeforeunload 事件的支援與觸發條件實現有差異

lingxyd_0發表於2012-01-14
 

問題描述

一般情況下,onbeforeunload 事件處理函式內會寫入一些提示性語句,當使用者的瀏覽器跳轉到其他頁面時,用來提醒使用者當前頁面將要跳轉,請使用者決定是否觀看新頁面。
或者在 onbeforeunload 事件內處理一些業務邏輯,在瀏覽器跳轉到新頁面之前 ,執行一些業務邏輯,如儲存使用者瀏覽資訊等。

簡單的說這個事件應僅在頁面 URL 發生變化時觸發,但是在 IE 中 使用 JavaScript 偽協議執行指令碼程式時,也會觸發 onbeforeunload 事件。

造成的影響

此問題不會造成大問題,但會導致不友好的提示出現,稍微影響使用者操作體驗。

受影響的瀏覽器

 

所有瀏覽器  

問題分析

onbeforeunload 事件是非 W3C DOM-Event 標準事件,它屬於 BOM (Browser Object Model) 範疇。到現在為止 BOM 還沒有被標準化,它由各個瀏覽器廠商制定,因此會有實現差異。

時至今日,HTML5 規範草案中已經開始標準化 BOM,遺憾的是 onbeforeunload 事件的觸發條件還沒有在草案中作出詳細說明。

更多內容可參考:6.1.6.2 Event handlers on elements, Document objects, and Window objects

最初的 onbeforeunload 事件支援是由 IE4.0 版本提供,存在於 BODY、FRAMESET 的 DOM 物件及 window 物件之中,隨後被其他瀏覽器複製,但具體事件觸發方式並沒有統一。

根據 MSDN 中描述,IE 的 onbeforeunload 事件可由以下這些條件觸發:

  • 關閉當前瀏覽器視窗。
  • 導航到另一個進入一個新的地址或選擇一個喜歡的位置。
  • 單擊後退,前進,重新整理,或主頁按鈕。
  • 點選一個連結到新頁面。
  • 呼叫 超連結的 click 方法。
  • 呼叫 document.write 方法。
  • 呼叫 document.open 方法。
  • 呼叫 document.close 方法。
  • 呼叫 window.close 方法。
  • 呼叫 window.open 方法,視窗名稱設定值為 _self。
  • 呼叫 window.navigate 或 NavigateAndFind 方法。
  • 呼叫 location.replace 方法。
  • 呼叫 location.reload 方法。
  • 指定一個 location.href 屬性的新值。
  • 使用 submit 按鍵提交表單,或呼叫 form.submit 方法。

更詳細的說明可以查考 MSDN 原文:onbeforeunload Event

在這些觸發條件中絕大多數都使頁面產生了跳轉,但還缺少一些常見情況說明,即頁面 URL 可能發生了變化但沒有產生跳轉。比如 "javascipt:" "mailto:" 等常見的瀏覽器內建偽協議,以及由第三方或使用者自定義的為協議時,頁面並不跳轉,而是根據偽協議執行指定的行為。這個情況應加入到觸發條件中。

根據以上所有這些觸發條件,我們構建如下程式碼來檢測各瀏覽器對 onbeforeunload 事件的支援程度與觸發條件:

<script>
window.onbeforeunload=function(){
  return "請點選取消留在此頁";
}
</script>
請手工關閉當前瀏覽器視窗。<br/>
請手工單擊後退,前進,重新整理,或主頁按鈕。<br/>
請手工在位址列輸入其他頁面地址或從收藏夾、歷史記錄中將頁面導航其他站點。<br/>
<a href="http://www.google.com" id="A">點選一個連結到新頁面</a><br />
<button onclick="document.getElementById('A').click()">呼叫 anchor.click 方法</button><br />
<button onclick="document.write('A')">呼叫 document.write 方法</button><br />
<button onclick="document.open()">呼叫 document.open 方法</button><br />
<button onclick="document.close()">呼叫 document.close 方法。</button><br />
<button onclick="window.open('http://www.google.com','_self')">呼叫 window.open方法,視窗名稱設定值為 _self。</button><br />
<button onclick="try{window.navigate('http://www.google.com')}catch(e){alert('不支援此方法')}">呼叫 window.navigate 方法</button><br />
<button onclick="try{window.external.NavigateAndFind('http://www.google.com','','')}catch(e){alert('不支援此方法')}">呼叫 NavigateAndFind 方法</button><br />
<button onclick="location.replace('http://www.google.com')">呼叫 location.replace 方法</button><br />
<button onclick="location.reload()">呼叫 location.reload 方法</button><br />
<button onclick="location.href='http://www.google.com'">指定一個 location.href 屬性的新值</button><br />
<form action="http://www.google.com" id="B">
<input type="submit" value="提交具有action屬性的一個表單">
</form>
<button onclick="document.getElementById('B').submit()">呼叫 form.submit 方法</button>
<a href="javascript:">呼叫 javascipt: 偽協議</a><br />
<a href="mailto:">呼叫 mailto: 偽協議</a><br />
<a href="custom:">呼叫自定義偽協議</a>

執行結果彙總入表:

 

  IE Firefox Chrome Safari Opera
關閉當前瀏覽器視窗 事件被觸發 事件被觸發 事件被觸發 不支援該事件
導航到另一個進入一個新的地址或選擇一個喜歡的位置 事件被觸發 事件被觸發 事件被觸發 不支援該事件
單擊後退,前進,重新整理,或主頁按鈕 事件被觸發 事件被觸發 事件被觸發 不支援該事件
點選一個連結到新頁面 事件被觸發 事件被觸發 事件被觸發 不支援該事件
呼叫 anchor.click方法 事件被觸發 不支援此方法1 不支援此方法1 不支援該事件
呼叫 document.write方法 事件被觸發 事件被觸發 事件未觸發 不支援該事件
呼叫 document.open方法 事件被觸發 事件被觸發 事件未觸發 不支援該事件
呼叫 document.close方法 事件未觸發 事件未觸發 事件未觸發 不支援該事件
呼叫 window.open方法,視窗名稱設定值為 _self 事件被觸發 事件被觸發 事件被觸發 不支援該事件
呼叫 window.navigate 事件被觸發 不支援此方法2 不支援此方法2 不支援該事件
呼叫 NavigateAndFind方法 事件被觸發 不支援此方法3 不支援此方法3 不支援此方法3
呼叫 location.replace 方法 事件被觸發 事件被觸發 事件被觸發 不支援該事件
呼叫 location.reload 方法 事件被觸發 事件被觸發 事件被觸發 不支援該事件
指定一個 location.href 屬性的新值 事件被觸發 事件被觸發 事件被觸發 不支援該事件
使用 submit 按鍵提交表單 事件被觸發 事件被觸發 事件被觸發 不支援該事件
呼叫 form.submit 方法 事件被觸發 事件被觸發 事件被觸發 不支援該事件
呼叫 javascipt: 偽協議 事件被觸發 事件未觸發 事件未觸發 不支援該事件
呼叫 mailto: 偽協議 事件未觸發 事件未觸發 事件被觸發 不支援該事件
呼叫自定義偽協議 事件被觸發 事件被觸發 事件被觸發 不支援該事件

注 1: 直接呼叫連結元素的 click 方法模擬滑鼠點選事件,只有 IE 和 Opera 支援,BX9052: IE Opera 支援使用 window.navigate 方法控制頁面跳轉SD9025: IE6 IE7 IE8 Opera 支援除 INPUT 和 BUTTON 元素以外的其他元素的 'click' 方法
注 2: 使用 window.navigate 方法導航網頁僅被 IE Opera 支援,可參考 MSDN 原文:navigate Method
注 3: NavigateAndFind 方法處於 window.external 物件中,external 物件也僅 IE 支援,可參考 MSDN 原文:NavigateAndFind Method 和本站文章BT9012: IE 的 external 物件提供的方法是 IE 特有的

結合彙總表可以看出:

  • Opera 並不支援 onbeforeunload 事件。
  • Chrome Safari 在呼叫 document.write、document.open、document.close 方法以及 "javascipt:" 偽協議時,不會觸發 onbeforeunload 事件。
  • Firefox 在呼叫 document.close 方法和 "javascipt:"、"mailto:" 偽協議時,不會觸發 onbeforeunload 事件。
  • IE 瀏覽器在呼叫 document.close 方法和 "mailto:" 偽協議時,不會觸發 onbeforeunload 事件。

解決方案

onbeforeunload 事件還未標準化,各瀏覽器的支援以及事件觸發條件差異較多,需謹慎使用。

如必須在非 Opera 瀏覽器內使用該事件,應儘量避免在頁面中呼叫常見的 "javascrpt:" 以及其他偽協議,以此迴避不同瀏覽器中 onbeforeunload 事件被頻繁觸發。

參見

知識庫

相關問題

測試環境

作業系統版本: Windows 7 Ultimate build 7600
瀏覽器版本: IE6
IE7
IE8
Firefox 3.6.10
Chrome 7.0.544.0 dev
Safari 5.0.2
Opera 10.62
測試頁面: onbeforeunload_event_differences.html
本文更新時間: 2010-10-13

關鍵字

javascipt URL Protocol onbeforeunload

 

轉載於:http://w3help.org/zh-cn/causes/BX2047

 

 

測試頁面程式碼:

 

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script>
window.onbeforeunload=function(){
	return "請點選取消留在此頁";
}
</script>
<body>
請手工關閉當前瀏覽器視窗。<br/>
請手工單擊後退,前進,重新整理,或主頁按鈕。<br/>
請手工在位址列輸入其他頁面地址或從收藏夾、歷史記錄中將頁面導航其他站點。<br/>
<a href="http://www.google.com" id="A">點選一個連結到新頁面</a><br />
<button onclick="try{document.getElementById('A').click()}catch(e){alert('不支援此方法')}">呼叫 anchor.click 方法</button><br />
<button onclick="document.write('A')">呼叫 document.write 方法</button><br />
<button onclick="document.open()">呼叫 document.open 方法</button><br />
<button onclick="document.close()">呼叫 document.close 方法。</button><br />
<button onclick="window.open('http://www.google.com','_self')">呼叫 window.open方法,視窗名稱設定值為 _self。</button><br />
<button onclick="try{window.navigate('http://www.google.com')}catch(e){alert('不支援此方法')}">呼叫 window.navigate 方法</button><br />
<button onclick="try{window.external.NavigateAndFind('http://www.google.com','','')}catch(e){alert('不支援此方法')}">呼叫 NavigateAndFind 方法</button><br />
<button onclick="location.replace('http://www.google.com')">呼叫 location.replace 方法</button><br />
<button onclick="location.reload()">呼叫 location.reload 方法</button><br />
<button onclick="location.href='http://www.google.com'">指定一個 location.href 屬性的新值</button><br />
<form action="http://www.google.com" id="B">
<input type="submit" value="提交具有action屬性的一個表單">
</form>
<button onclick="document.getElementById('B').submit()">呼叫 form.submit 方法</button><br />
<a href="javascript:">呼叫 javascipt: 偽協議</a><br />
<a href="mailto:">呼叫 mailto: 偽協議</a><br />
<a href="custom:">呼叫自定義偽協議</a>
</body>
</html>


 

 

 

 

相關文章