- 裝置: iOS: 16.1.1
- User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Mobile/15E148 Safari/604.1
問題重現步驟:
- 使用 iOS 16.1.1 Safari 開啟 test1.html
- 點選 Link 超連結跳轉到 test2.html
- 在 test2.html 回退到 test1.html
期望的結果是看到 alert 對話方塊。
問題在 iOS 15 不能重現。
test1.html 的原始碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test1</title>
</head>
<body>
<a href="test2.html">Link</a>
</body>
</html>
test2.html 的原始碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test2</title>
</head>
<body>
<button id="btn">history.back()</button>
<script>
history.pushState(null, null, null)
window.addEventListener("popstate", _ => alert(1))
document.getElementById("btn").addEventListener("click", _ => {
history.back()
}, false)
</script>
</body>
</html>
我在好幾個瀏覽器上做了測試:
我剛試過,也可以在 macOS 上重現。
我在單擊 history.back()
按鈕時看到 alert,但在單擊後退按鈕(或向後滑動)時看不到 alert。
對於 history.back() 和透過瀏覽器 UI 向後導航之間的行為差異,我還沒有任何解釋(儘管我懷疑這與我們所做的一些後退/前進列表劫持預防工作有關)。
我還注意到我們的行為似乎與 Chrome 一致。 因此,如果有錯誤,那不是 WebKit 特有的。
Firefox 似乎始終如一地顯示 alert,正如 Web 開發人員所期望的那樣。
StackOverflow 上相關的討論。
結論
哦,我只是更仔細地檢視了測試用例,我明白了現在發生了什麼。
與 Chrome 類似,WebKit 最近做了一些安全加固,以防止不良的 JavaScript 劫持後退/前進列表。 這意味著由 JS 新增的歷史條目(例如透過 history.pushState())在使用者導航時會被跳過,除非它們是透過使用者互動新增的。
在測試用例中,test2.html 在沒有使用者互動的情況下呼叫 history.pushState()。 結果,建立的歷史記錄項被標記了一個特殊的標誌。 如果使用者向後滑動或按下後退按鈕,我們將跳過這個“虛擬”歷史記錄項,因此不會觸發 popstate 事件。 這是新的故意行為,應該與 Blink 保持一致。
如果不希望跳過歷史記錄項,則在呼叫 history.pushState() 時需要使用者手勢/啟用(例如,由於使用者單擊按鈕而呼叫 history.pushState())。