壹 ❀ 引
登錄成功后跳轉到上一個頁面是很常見的需求,比如在天貓添加購物車時網站會效驗用戶登錄情況,若未登錄則跳轉登錄,登錄成功返回到先前的商品頁。
這個功能實現並不困難,但因為我的奇思妙想讓我先后了解了window.history
對象以及窗口關閉/離開事件onbeforeunload
,那么讓這個需求做個引子,讓我們開始一次有趣的探索之旅。
貳 ❀ 有趣的onbeforeunload
不管是從什么頁面進入的登錄頁,總是得先有個離開頁面的過程,那我在離開前一個頁面時先記住頁面,登錄成功調回來不就好了,所以我第一就想到了onbeforeunload
事件。
關於onbeforeunload
事件,MDN上說的很詳細,此事件在窗口即將被關閉(關閉瀏覽器 / 跳轉到其它頁面)時會觸發,看個例子:
window.onbeforeunload = function () {
console.log('頁面要離開了。');
};
復制此代碼到瀏覽器控制台並回車執行,之后無論我們跳轉或關閉窗口,你會發現console
都會執行。
onbeforeunload
事件的使用場景其實很多,比如博客園博離開未保存的博客編輯窗口,再如信息較多的表單填寫等等,onbeforeunload
主要起防止誤操作丟失頁面的作用,多一次挽回的機會。
值得一提的是onbeforeunload
事件中無法使用window.open()
以及window.alert()
方法,若你使用,瀏覽器會拋出blocked xxxx during beforeunload
類似的錯誤,意思就是在瀏覽器關閉前禁止使用彈窗或打開新窗口。
我們前面又說常用於離開頁面給出友好彈窗提示,不能用alert
怎么實現呢,得換一種方式,這里貼出代碼:
window.onbeforeunload = function (e) {
var e = e || window.event,
dialogText = '頁面還未保存,確定要離開嗎?';
// 兼容IE8和Firefox 4之前的版本
if (e) {
e.returnValue = dialogText;
};
// Chrome, Safari, Firefox 4+, Opera 12+ , IE 9+
return dialogText;
};
當你運行這段代碼並嘗試關閉頁面時,你會看到頁面確實給出了如下提示:

但提示文字並沒有使用我們自己定義語句,這是因為瀏覽器在之后的版本中已統一提示語句,自定義語句只在低版本瀏覽器適用。
onbeforeunload
這么好用,兼容性怎么樣呢,通過 can i use 一查,兼容性非常出色,完美兼容 IE6。
那么我有沒有使用onbeforeunload
來處理登錄成功返回上個頁面呢?很遺憾並沒有,A頁面跳B頁面,B頁面跳C頁面,只要頁面跳轉此事件都會觸發,頁面跳轉本身就屬於高頻操作,性能代價太大。
叄 ❀ 歷史的掌控者history
我突然靈機一動!!!干嘛要自己去記錄頁面跳轉呢,window.history
不是已經幫我們做了這件事嗎,想想還有點小激動。
打開瀏覽器控制台,輸入window.history
並回車,可以看到如下屬性:

因為隱私問題,history對象早已不再展示用戶瀏覽記錄列表,只保留了go,back,forward
以及HTML5
新增的pushState
與replaceState
方法用於操作頁面記錄。說通俗點,記錄我不給你看,但允許你操作。
新增的兩個方法我們先不說,這里主要說說前三個。我們來做個小實驗,先打開百度,跳轉到嗶哩嗶哩,再跳轉到騰訊視頻。現在打開控制台,輸入window.history.back()
並回車,你會發現頁面從騰訊視頻跳到了嗶哩嗶哩。按下方向鍵 ↑ 再回車,頁面又回到了最初的百度。
現在輸入window.history.forward()
並回車,頁面又會跳到B站,重復此操作,B站又跳到騰訊視頻。

其實不難理解,假設已經建立了A-B-C
三個節點,使用back
就是從此節點往回退,相反的,forward
就是從此節點往前進。
我們在騰訊視頻頁面輸入window.history.go(-2)
,你會發現一下回到了百度,因為它等同於執行了2次back
方法。對應的,輸入window.history.go(2
)回車,頁面又能從百度回到騰訊,它等同於執行了2次forward
方法,是不是很簡單。
於是我就想到了這樣的邏輯:
function login() {
//do something...
//返回上個頁面
window.history.back();
};
於是某位用戶將網站的登錄頁添加到了收藏夾,打開瀏覽器顯示百度首頁,點擊收藏夾跳轉登錄頁,登錄成功后於是網站跳轉百度,用戶一臉懵逼....
很遺憾,history pass,不符合要求。
肆 ❀ 我的實現
使用onbeforeunload
每個頁面都會觸發,性能不好,使用history
我們是不用記錄了,結果記錄不受網站控制,網站外部也會記。那么我們就綜合一下,需要記錄的時候我們自己記。
一共也就兩個地方需要記憶,我們知道登錄一般都在頁頭,你想進入登錄頁必須點擊登錄按鈕,那么這個時候記錄就好了。
第二種情況就是程序跳轉登錄頁,比如token
過期自動跳轉提示登錄,那么在程序中需要跳轉的地方也去記錄。
因為登錄屬於全站性的操作,你也不知道用戶在哪個頁面進入的登錄,所以像我這邊使用angularjs
開發的項目,就在總module
上注冊一個登錄相關的service,這里只說具體方法實現:
// 在跳轉登錄前調用,用於記錄當前頁面
function localStorgeUrl() {
//取當前頁面地址,這里模擬是百度
// let pathArr = window.location.pathname.split('/');
// let url = pathArr[pathArr.length - 1];
let url = 'http://www.baidu.com';
//本地存儲該頁面
window.localStorage.setItem('url', url);
};
function redirectUrl() {
//獲取緩存路徑
let url = window.localStorage.getItem('url');
//假設用戶從外網進入登錄頁,取不到的情況跳轉首頁
url ? location.href = url : location.href = 'index.html';
};
//登錄
function login() {
// 登錄相關操作,假設登錄成功
redirectUrl();
};
//跳轉登錄頁前調用
localStorgeUrl();
//開始登錄
login();
這里只是貼一個思路,如果有緣人看到有更好的做法,也歡迎討論。本文從實現功能登錄成功返回上個頁面為引子,介紹了頁面關閉事件onbeforeunload與history,也算一次不錯的學習,那么就寫到這里。