前言
1.主要是返回是預設的瀏覽器返回事件是返回上一個頁面。
2.處理頁面各種彈窗,點選物理返回應該隱藏這些彈窗而不是直接返回頁面。
3.總結下問題,h5應該希望能監聽到返回事件並且做一些處理。
相關知識
1、利用popstate
事件,點選瀏覽器前進,後退會觸發popstate事件。
2、利用hashchange
事件,頁面hash改變是會觸發此事件(適合react,vue單頁面應用)。
一、window.onpopstate
每當處於啟用狀態的歷史記錄條目發生變化時,popstate
事件就會在對應window
物件上觸發. 如果當前處於啟用狀態的歷史記錄條目是由history.pushState()
方法建立,或者由history.replaceState()方法修改過
的, 則popstate事件物件的state
屬性包含了這個歷史記錄條目的state物件的一個拷貝.呼叫
history.pushState()
或者history.replaceState()
不會觸發popstate事件.popstate
事件只會在瀏覽器某些行為下觸發, 比如點選後退、前進按鈕(或者在JavaScript中呼叫history.back()、history.forward()、history.go()
方法).
history.pushState()
不會重新整理頁面,往歷史記錄中新增一條記錄。
history.replaceState()
不會重新整理頁面,替換當前頁面記錄,不會在歷史記錄中新增。相容性:當網頁載入時,各瀏覽器對
popstate
事件是否觸發有不同的表現,Chrome 和 Safari會觸發popstate
事件, 而Firefox不會.
假如當前網頁地址為example.com/example.htm…,則執行下述程式碼後:
window.onpopstate = () => {} 等同於 window.addEventListener('popstate',() => {});
window.onpopstate = function(event) {
alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
};
//繫結事件處理函式.
history.pushState({page: 1}, "title 1", "?page=1"); //新增並啟用一個歷史記錄條目 http://example.com/example.html?page=1,條目索引為1 當前記錄有兩條記錄(包括最開始的)
history.pushState({page: 2}, "title 2", "?page=2"); //新增並啟用一個歷史記錄條目 http://example.com/example.html?page=2,條目索引為2 當前記錄有三條記錄
history.replaceState({page: 3}, "title 3", "?page=3"); //修改當前啟用的歷史記錄條目 http://ex..?page=2 變為 http://ex..?page=3,條目索引為3 當前記錄有三條(replaceState會替換第三條條)
history.back(); // 彈出 "location: http://example.com/example.html?page=1, state: {"page":1}"
history.back(); // 彈出 "location: http://example.com/example.html, state: null
history.go(2); // 彈出 "location: http://example.com/example.html?page=3, state: {"page":3}
複製程式碼
如上圖,假設當前頁面是A頁面,跳轉到B頁面,B頁面開啟dialong彈窗,這個時候點選返回,預設是返回到A頁面。這種體驗是很差的,優化體驗,這個時候需要優化這種體驗效能問題。
場景:在B頁面中有個彈窗,點選返回,要關閉彈窗,再次點選,返回到A頁面。
程式碼如下:
// 假設A頁面為http://www.example.com/a.html
// B頁面是http://www.example.com/b.html
// 下面以react生命週期為例
componentDidMount: function() {
window.addEventListener('popstate',(state) => {
// 監聽到返回事件,注意,只有觸發了返回才會執行這個方法
console.log(state);
this.back();
})
}
// 假設點選開啟對話窗,利用pushState新增一天記錄
openDialong: function() {
// 此時頁面地址為b.html?page=1,但是頁面沒有重新整理。並且不會觸發popstate方法
history.pushState({page: 1}, "title 1", "?page=1");
// TODO
}
// 彈窗已存在,並且點選了返回事件,此時頁面b.html?page=1--->b.html,並觸發popstate事件
back: function() {
// 頁面在使用者看來是沒有重新整理的,此時是關閉dialong
// TODO
}
// 離開頁面的時候取消監聽popstate
componentWillUnmount: function() {
window.removeEventListener('popstate',(state) => {
this.back();
})
}複製程式碼
二、window.onhashchange
當 一個視窗的 hash (URL 中 # 後面的部分)改變時就會觸發 hashchange 事件(參見
location.hash
)。
if ("onhashchange" in window) { alert("該瀏覽器支援 hashchange 事件!"); } function locationHashChanged() { if (location.hash === "#somecoolfeature") { somecoolfeature(); } } window.onhashchange = locationHashChanged;複製程式碼
還是以上面場景為例:
// 假設A頁面為http://www.example.com/a.html#/a
// B頁面是http://www.example.com/a.html#/b
// 下面以react生命週期為例
componentDidMount: function() {
window.addEventListener('hashchange',(state) => {
// hash改變就會觸發
const href = location.href;
// 當前hash中不存在?page=1是觸發(初始化剛進來是不會觸發這個方法的)
if (href.indexOf('?page=1') < 0) {
this.back();
}
})
}
// 假設點選開啟對話窗,利用pushState新增一天記錄
openDialong: function() {
// 此時頁面地址為a.html?page=1,但是頁面沒有重新整理。並且不會觸發popstate方法
// history.pushState({page: 1}, "title 1", "?page=1");
// 不過此時會觸發hashchange,但是加個判斷;
this.props.history.push('/b?page=1');
// TODO
}
// 彈窗已存在,並且點選了返回事件,此時頁面a.html?page=1--->a.html,並觸發hashchange事件
back: function() {
// 頁面在使用者看來是沒有重新整理的,此時是關閉dialong
// TODO
}
// 離開頁面的時候取消監聽hashchange
componentWillUnmount: function() {
window.removeEventListener('hashchange',(state) => {
this.back();
})
}
複製程式碼
三、優化**
還是這個圖片
假設A是首頁,B詳情頁面,C是支付頁面,D是結果頁面。(我們希望D不能返回到C頁面)。
假設要從D頁面跳轉到B頁面(B,C,D也一樣), 從結果頁面D中點選按鈕跳轉到詳情B頁面,可再次購買。
有以下方法:
方法一:location.href = 'http://www.example/b.html';
方法二:history.go(-2);複製程式碼
主要區別:
方法一會往歷史記錄中新增新的記錄,變成A—>B—>C—>D—>B。
此時點選物理返回,就會回到D頁面。而這不是我們要的結果。
方法二是回到歷史記錄中,不會新增記錄,鏈路還是A—>B—>C—>D。
D頁面不應該回到C頁面
此時我們就可以用到上面的方法,點選返回利用history.go()的方法,回到我們想到的頁面。
// D頁面---->B頁面
componentDidMount: function() {
this.props.history.push('/b?page=1');
// 如果有問題,加個setTimeout
window.addEventListener('hashchange',(state) => {
// hash改變就會觸發
const href = location.href;
// 當前hash中不存在?page=1是觸發(初始化剛進來是不會觸發這個方法的)
if (href.indexOf('?page=1') < 0) {
this.back();
}
})
}
// 並且點選了返回事件,此時頁面d.html?page=1--->d.html,並觸發hashchange事件
back: function() {
// 頁面在使用者看來是沒有重新整理的,此時是回到B頁面
// TODO
this.props.history.go(-2);
}
// 離開頁面的時候取消監聽hashchange
componentWillUnmount: function() {
window.removeEventListener('hashchange',(state) => {
this.back();
})
}複製程式碼
有問題歡迎指正。