本文為純原創(chuàng),如需轉(zhuǎn)載,請注明來源。2019年5月31日 09:13:58
說在前面的話
如果你當(dāng)前使用的庫是JQuery,那請參考我前面的文章<<JavaScript監(jiān)聽安卓物里返回鍵>>
如果是Vue-Cli(不是UMD引入的Vue),請繼續(xù)往下看。
當(dāng)我們向控制物理返回鍵(之后簡稱返回鍵)的時候,無非是想實現(xiàn)兩種功能:
1、 用戶點按返回鍵,不返回到上級頁面,且不進行任何操作,達到禁用返回鍵的目的。
2、用戶點按返回鍵,不返回到上級頁面,但跳轉(zhuǎn)到其它頁面,或者執(zhí)行其它內(nèi)置方法,達到改寫返回鍵的目的。
但由于在Vue項目中,控制頁面跳轉(zhuǎn)使用的是Router,如果直接在public/index.html中添加前文的方法,就會導(dǎo)致物理返回鍵被絕對控制,無法動態(tài)修改的問題。
而如果把前文的方法寫到App.vue中,再在每個頁面按需調(diào)用這個方法,則又會出現(xiàn)事件重復(fù)疊加的bug。
我也苦惱了好一陣,最后找到了個人認(rèn)為比較完美的解決方案。
話不多說。
并未直接給出代碼,而是從實現(xiàn)原理講解。
1. 要實現(xiàn)前文中的pushHistory()方法
不同于傳統(tǒng)JS的是,當(dāng)我們在Vue項目中控制頁面跳轉(zhuǎn)時,為了不破壞Vuex中的數(shù)據(jù),會使用this.$router.push() 來代替 window.location.href
而當(dāng)我們按照前文中提到的方法使用后,發(fā)現(xiàn)vue生成的地址被完整替換掉了。
如圖:



可見,使用前文方法后,由Router生成的hash被破壞掉了,雖然我未發(fā)現(xiàn)這對當(dāng)前頁面有什么影響,但這一定是不可取的。
隨后我修改了這個方法如下:
function pushHistory(){
var state = {
title:"title",
url:window.location.hash};
window.history.pushState(state,"title",window.location.hash);
}
pushHistory()
并把它添加到了index.html里。
因為添加到index.html之后,我的pushHistory()將變成全局可以調(diào)用的方法,因為Vue會將所有的.vue文件渲染到這個index.html中。
我使用 window.location.hash替換掉了#,這樣以保證Router生成的hash不被破壞掉。

該js代碼添加的位置一定要在head中,否則根據(jù)執(zhí)行順序,如果寫到了body后面,Vue是調(diào)取不到的。
2. 要有一個方法,可以在Vue的任何頁面中調(diào)用,以用于攔截window.onpopstate請求,并且動態(tài)執(zhí)行我們要執(zhí)行的方法。
要實現(xiàn)一個在Vue個頁面中可以調(diào)用的方法很簡單,我們只要寫帶main.js中,再將它掛到原型鏈上即可。
代碼如下:
function gotoURL(callback){
window.onpopstate = null;
window.onpopstate = function(){
callback()
}
}
Vue.prototype.gotoURL = gotoURL
main.js如圖

請只看紅框內(nèi)的代碼,不要在意別的。
3、調(diào)用
注意:請不要在App.vue中調(diào)用,因為App.vue只是其它頁面的容器,只會被一次渲染, 我們在配置Router的時候,一般路徑為'/'的頁面會被直接渲染到App.vue中,所以當(dāng)我們要控制初始頁面的返回鍵,需要找到對應(yīng)的vue文件中調(diào)用方法,而不是在App.vue中調(diào)用方法。
調(diào)用一般為 一個頁面一次性調(diào)用,意思就是在頁面渲染的時候,我們就要調(diào)用這個方法。
所以我要(建議)將調(diào)用的方法寫到mounted周期中。如下:
mounted() {
let that =this;
pushHistory() // 必須存在
that.gotoURL(function () {
pushHistory() // 必須存在
console.log('666') // 點擊返回鍵要執(zhí)行的方法
})
}
為什么要把pushHistory調(diào)用兩次?
我也曾刪掉它們之中的任何一個,但是會出現(xiàn)返回鍵無法正??刂频膯栴},所以先加上,后期如果有更好方法,我會發(fā)上來。
不要濫用這個方法,只在需要的頁面中使用,不需要的頁面中請不要調(diào)用,以防出現(xiàn)問題。
產(chǎn)品設(shè)計建議: PM在設(shè)計產(chǎn)品時,請要考慮移動端的一些問題,盡量避免硬核控制返回鍵的情況出現(xiàn)。
如果讀者有其它需要,可以通過我的簡書首頁簽名下方的微信二維碼添加我好友,請注明來意。
補:
有的朋友問我為什么使用DOM0事件控制popstate而不是DOM2,因為DOM2無法解綁匿名函數(shù),因為我在不同頁面代進來的callback是不一樣的。使用DOM2會出現(xiàn)事件疊加。根據(jù)事件機制,所以使用DOM0,讓每一次的事件都替換上一次的事件。
而在傳統(tǒng)的JS中為什么可以使用DOM2,是因為每一個頁面都切換了運行環(huán)境,所以前一個頁面的DOM2不會和當(dāng)前頁面的DOM2相疊加。