﻿# 如何避免使用者在特定網頁表單在未經送出時意外離開

這是個簡單的 JavaScript 小技巧且不常用，昨天有個客戶提到需要提醒使用者當資料編輯到一半突然試圖離開網頁時需要提醒使用者是否真的要離開此網頁，以避免輸入到一半的表單資料就此消失，以下是一些撰寫類似功能的心得與注意事項。

在 [DHTML Events](http://msdn.microsoft.com/en-us/library/ms533051\(VS.85\).aspx) 中有兩個跟 unload 有關的事件，分別陳述如下：

-   [onbeforeunload Event](http://msdn.microsoft.com/en-us/library/ms536907\(VS.85\).aspx)
    -   當 window, body, frameset 物件「被卸載之前」會先引發這個事件。
-   [onunload Event](http://msdn.microsoft.com/en-us/library/ms536973\(VS.85\).aspx)
    -   當 window, body, frameset 物件「被卸載之後」才會引發這個事件。

當頁面嘗試離開時會先將所有 DOM 物件卸載(unload)，所以由上述說明你可以知道你「應該」把避免離開網頁的事件寫在 [onbeforeunload Event](http://msdn.microsoft.com/en-us/library/ms536907\(VS.85\).aspx) 裡才能攔截網頁離開的動作，若寫在 [onunload Event](http://msdn.microsoft.com/en-us/library/ms536973\(VS.85\).aspx) 就來不及了，因為物件已卸載，網頁就會離開。

[onbeforeunload Event](http://msdn.microsoft.com/en-us/library/ms536907\(VS.85\).aspx) 的使用方式有其特殊性，所以操作方法可能會跟你想像的不太一樣，我先提供一個「錯誤範例」如下：

```
window.document.body.onbeforeunload = function()
{
    if(confirm('您尚未將編輯過的表單資料送出，請問您確定要離開網頁嗎？'))
    {
        return true;
    }
    else
    {
        return false;
    }
}
```

當你在網頁中按下 F5 重新整理或點選其他連結試圖離開網頁時，就會先出現以下畫面：

![網頁訊息：您尚未將編輯過的表單資料送出，請問您確定要離開網頁嗎？](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/c66fb05e53f169dd62db-image_7.png "網頁訊息：您尚未將編輯過的表單資料送出，請問您確定要離開網頁嗎？")

這時當你按下 \[**確定**\] 按鈕會出現以下視窗：

![Windows Internet Explorer: 您確定要離開這個網頁瀏覽](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/1e0f2bc81e95118e0bb8-image_8.png "Windows Internet Explorer: 您確定要離開這個網頁瀏覽")

這時當你按下 \[**取消**\] 按鈕會出現以下視窗：

 ![Windows Internet Explorer: 您確定要離開這個網頁瀏覽](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/3f8fbf998afcb354a917-image_9.png "Windows Internet Explorer: 您確定要離開這個網頁瀏覽")

也就是不管你怎麼選都會出現視窗兩次，這是很詭異的現象，所以這是錯誤示範。

由於「使用者」想「離開網頁」，基於「使用者最大」的原則，瀏覽器不可能真正擋住使用者的去路，所以你的 JavaScript 是不可能「絕對阻擋」網頁離開，你只能「提醒」使用者離開此網頁，所以正確的寫法是在 function 中 return 一段字串訊息即可，如下範例：

```
window.document.body.onbeforeunload = function()
{
    return '您尚未將編輯過的表單資料送出，請問您確定要離開網頁嗎？';
}
```

當你在網頁中按下 F5 重新整理或點選其他連結試圖離開網頁時，就會先出現以下畫面：

![Windows Internet Explorer: 您確定要離開這個網頁瀏覽](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/ade5fcf6d2d2eec37153-image_15.png "Windows Internet Explorer: 您確定要離開這個網頁瀏覽")

但是你有沒有發現如上圖的文字共有三行，中間那行才是你自己寫的文字，但由於被上、下兩行文字夾住，所以比較不容易凸顯你想說明的內容，所以我通常會用些特殊符號讓訊息凸顯，讓使用者可以更容易看見我想寫的字（ 但使用者通常不看字 = ='' ），修改後範例如下：

```
window.document.body.onbeforeunload = function()
{
    return '★★ 您尚未將編輯過的表單資料送出，請問您確定要離開網頁嗎？ ★★';
}
```

![Windows Internet Explorer: 您確定要離開這個網頁瀏覽](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/219e6d8516f85834a0db-image_18.png "Windows Internet Explorer: 您確定要離開這個網頁瀏覽")

最後，還有個重點觀念，也就是當 [onbeforeunload](http://msdn.microsoft.com/en-us/library/ms536907\(VS.85\).aspx) 事件被觸發的同時，如果也有其他事件被觸發的話，在其他事件中**不能再修改任何 DOM 物件**，因為物件處於**正在卸載**的狀態，所以當你在其他事件中要執行類似的修改動作，就會影發「未指定的錯誤」的錯誤訊息，如下圖所示：

![未指定的錯誤](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/ca697db96a51788e3c48-image_21.png "未指定的錯誤")

所以在撰寫時必須特別注意這個潛在可能發生的錯誤。

當你要進行表單送出時總不能還出現這個離開網頁的提示框吧！所以你還必須在表單的 Submit 按鈕特別加上一段 JavaScript 將 事件取消。

```
<input type="submit" value="送出" 
       onclick="window.document.body.onbeforeunload=null;return true;" />
```

如此一來這個功能就完成了。

**相關連結**

-   [MSDN - HTML and DHTML Reference](http://msdn.microsoft.com/en-us/library/ms533050\(VS.85\).aspx)
-   [onbeforeunload Event](http://msdn.microsoft.com/en-us/library/ms536907\(VS.85\).aspx)
-   [onunload Event](http://msdn.microsoft.com/en-us/library/ms536973\(VS.85\).aspx)
