iT邦幫忙

2024 iThome 鐵人賽

DAY 17
0
Modern Web

轉生成前端工程師後,30步離開新手村!系列 第 17

# 前端實作案例分享: 攔截瀏覽器回上一頁

  • 分享至 

  • xImage
  •  

提問: 我希望使用者按下瀏覽器的回上一頁或是重新整理時,能夠先跳出一個確認訊息,提醒使用者之後再讓他選擇是否離開該怎麼做?

https://ithelp.ithome.com.tw/upload/images/20241001/20169487ksNzJRHzAf.png

我們可以利用Window History Event中的 popstatebeforeunload搭配History API來做到這件事情。


實作方式:

Angular 為例,我們可以透過 @HostListener 監聽 popstatebeforeunload 事件。

首先討論 popstate,監聽 popstate 主要目的是為了抓取使用者透過回上一頁、前往下頁或是透過 history.pushStatehistory.popState 觸發的頁面切換。

/**
 * 監聽瀏覽器的回上一頁
 */
@HostListener('window:popstate', ['$event'])
onPopState(event: PopStateEvent): void {
	if (!window.confirm('要回到上一頁嗎?系統可能不會儲存您所做的變更')) {
		history.go(1);
	}
}

收到 popstate 事件後,透過 window 開啟了 confirm 窗口。如果使用者的回覆是取消的話,就透過 History API 前往下一個瀏覽紀錄。為什麼要前往下一個紀錄呢?

因為 popstate 事件的主要目的是讓開發者能夠回應歷史記錄的變化,而不是防止這些變化。這意味著一旦用戶決定導航到前一頁或下一頁,事件就會自動觸發。

並且,瀏覽器的歷史導航功能是為了提升用戶體驗,允許用戶在他們的瀏覽歷史中自由地前進和後退,因此在 popstate 事件中並沒有提供任何直接的方法來取消或阻擋這個事件。

於是我們雖然可以在監聽到 popstate 並且在觸發當下透過彈窗暫定程式執行,但無論使用者怎麼選擇,其實都已經回到前一頁了。所以才會有 history.go(1) 的部分。

接著是 beforeunload 的部分,監聽 beforeunload 的目的是為了攔截使用者透過重新整理、關閉分頁、輸入網址直接導頁等方式離開頁面。

/**
 * 監聽瀏覽器的重新載入和關閉分頁
 */
@HostListener('window:beforeunload', ['$event'])
onBeforeunload(event: BeforeUnloadEvent): void {
  event.preventDefault();
  event.returnValue = '';
}

收到 beforeunload 事件後,我們透過 preventDefault 來阻止默認的行為,並且透過 event.returnValue 設置返回值來觸發瀏覽器顯示提示訊息,提醒使用者即將離開頁面。

透過上述的兩項監聽,即可做到在使用者離開頁面時跳出彈窗提醒使用者,並在使用者確認要離開後才離開,按下取消則回停留在當前頁面。特別注意的是,popstate 是針對離開當前頁面再回來的,所以若有資料或狀態,記得搭配快取進行處理。

下方補充一下,實作此功能所用到的相關知識科普,總共有瀏覽器的路由機制、WindowHistory eventsHistory API


瀏覽器的路由機制:

在瀏覽器中,從網址輸入之後到最終顯示網頁會經過很多階段,大致如下:

  • URL 輸入:
    用戶在瀏覽器的地址欄輸入 URL,並按下 Enter 鍵。
  • DNS 查詢:
    瀏覽器會檢查本地緩存中是否有對應的 IP 地址。如果沒有,則發送 DNS 查詢請求到 DNS 伺服器,尋找對應的 > IP 地址。
  • 建立 TCP 連接:
    瀏覽器與伺服器之間建立 TCP 連接,這通常使用三次握手(Three-way Handshake)進行。這個過程涉及 > > SYN、SYN-ACK 和 ACK 三個步驟。
  • 發送 HTTP 請求:
    TCP 連接建立後,瀏覽器會向伺服器發送 HTTP 請求,請求特定的網頁資源。
  • 伺服器響應:
    伺服器接收到請求後,處理請求並返回 HTTP 響應,包括狀態碼(例如 200 表示成功)和請求的資源(例如 HTML 文件)。
  • 內容渲染:
    瀏覽器接收到響應後,開始解析 HTML 內容。這包括解析 CSS 和 JavaScript 代碼,以及加載圖像和其他資源。
  • DOM 和 CSSOM 建立:
    瀏覽器會根據 HTML 內容構建文檔物件模型(DOM)和 CSS 物件模型(CSSOM)。
  • 渲染和顯示:
    在完成 DOM 和 CSSOM 的構建後,瀏覽器會進行佈局計算,將內容渲染到螢幕上。

並且在這些階段中,有些階段會觸發 Window Event,而我們則可以監聽這些 Event 作為判斷使用者是否正要離開或是回上一頁的依據。


Window 的 History events:

主要有以下項目:

  • hashchange
    觸發情況:當 URL 的 hash(# 後的部分)改變時觸發。
    用途:用於處理基於 hash 的變化,適合用於 SPA(單頁應用程式),可用於更新頁面內容而無需重載整個頁面。
  • popstate
    觸發情況:當用戶使用瀏覽器的「返回」或「前進」按鈕導航到歷史記錄中的不同條目時觸發。
    用途:用於根據當前歷史狀態更新頁面內容,特別是在使用 history.pushState() 或 history.replaceState() 方法修改歷史狀態時。
  • beforeunload
    觸發情況:當用戶嘗試離開當前頁面或重新加載頁面時觸發。
    用途:可以用來顯示確認提示,防止用戶意外離開頁面,尤其是在未保存更改的情況下。
  • unload
    觸發情況:在文檔即將被卸載(離開或關閉)時觸發。
    用途:用於清理工作,如關閉網路連接或清除定時器。注意,在這個事件中執行的代碼可能會有時間限制。
  • load
    觸發情況:當整個頁面(包括所有依賴的資源如樣式表和圖片)完全加載後觸發。
    用途:通常用於執行需要等到所有資源都加載完成的代碼,如初始化應用或顯示內容。
  • pageshow
    觸發情況:當頁面被顯示(包括從歷史記錄恢復時)時觸發。
    用途:用於管理頁面的顯示狀態,特別是在從歷史堆棧中返回時可以恢復頁面狀態。
  • pagehide
    觸發情況:當頁面即將被隱藏(如導航到另一個頁面)時觸發。
    用途:可以用於清理或保存頁面狀態,以便在用戶返回時能夠恢復。
  • pageswap
    觸發情況:當頁面交換時觸發(此事件不是所有瀏覽器都支持,主要在特定框架中使用)。
    用途:用於在 SPA 中管理頁面之間的切換,保持狀態的更新。

History API:

History API 是瀏覽器提供的一組方法,用於操作瀏覽器的歷史記錄,從而實現無需重新加載頁面即可更改 URL 的功能。主要的歷史紀錄相關方法包括:

  • history.pushState(state, title, url)
    在歷史紀錄中推入新的狀態,並改變當前的 URL。
    state 可以是任何數據對象,用於在不同狀態間傳遞數據。
  • history.replaceState(state, title, url)
    替換當前的歷史紀錄,而不創建新的歷史紀錄。
  • history.go(num)
    在歷史紀錄中移動指定數量的條目。

攔截回上一頁事件的功能到這邊就結束了,下一篇文章我們就來談談如何使用 Store 來實作存在 Angular 應用生命週期的快取機制吧!


上一篇
# 前端實作案例分享: Flex Box應用
下一篇
# 前端實作案例分享:  透過Store進行頁面緩存
系列文
轉生成前端工程師後,30步離開新手村!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言