本文為純?cè)瓌?chuàng),如需轉(zhuǎn)載陌知,請(qǐng)注明來源。2019年5月31日 09:13:58
說在前面的話
如果你當(dāng)前使用的庫是JQuery掖肋,那請(qǐng)參考我前面的文章<<JavaScript監(jiān)聽安卓物里返回鍵>>
如果是Vue-Cli(不是UMD引入的Vue)仆葡,請(qǐng)繼續(xù)往下看。
當(dāng)我們向控制物理返回鍵(之后簡(jiǎn)稱返回鍵)的時(shí)候志笼,無非是想實(shí)現(xiàn)兩種功能:
1沿盅、 用戶點(diǎn)按返回鍵,不返回到上級(jí)頁面纫溃,且不進(jìn)行任何操作腰涧,達(dá)到禁用返回鍵的目的。
2紊浩、用戶點(diǎn)按返回鍵窖铡,不返回到上級(jí)頁面,但跳轉(zhuǎn)到其它頁面坊谁,或者執(zhí)行其它內(nèi)置方法费彼,達(dá)到改寫返回鍵的目的。
但由于在Vue項(xiàng)目中口芍,控制頁面跳轉(zhuǎn)使用的是Router箍铲,如果直接在public/index.html中添加前文的方法,就會(huì)導(dǎo)致物理返回鍵被絕對(duì)控制鬓椭,無法動(dòng)態(tài)修改的問題颠猴。
而如果把前文的方法寫到App.vue中,再在每個(gè)頁面按需調(diào)用這個(gè)方法小染,則又會(huì)出現(xiàn)事件重復(fù)疊加的bug芙粱。
我也苦惱了好一陣,最后找到了個(gè)人認(rèn)為比較完美的解決方案氧映。
話不多說春畔。
并未直接給出代碼,而是從實(shí)現(xiàn)原理講解岛都。
1. 要實(shí)現(xiàn)前文中的pushHistory()方法
不同于傳統(tǒng)JS的是律姨,當(dāng)我們?cè)赩ue項(xiàng)目中控制頁面跳轉(zhuǎn)時(shí),為了不破壞Vuex中的數(shù)據(jù)臼疫,會(huì)使用this.$router.push() 來代替 window.location.href
而當(dāng)我們按照前文中提到的方法使用后择份,發(fā)現(xiàn)vue生成的地址被完整替換掉了。
如圖:
可見烫堤,使用前文方法后熔吗,由Router生成的hash被破壞掉了,雖然我未發(fā)現(xiàn)這對(duì)當(dāng)前頁面有什么影響凿滤,但這一定是不可取的。
隨后我修改了這個(gè)方法如下:
function pushHistory(){
var state = {
title:"title",
url:window.location.hash};
window.history.pushState(state,"title",window.location.hash);
}
pushHistory()
并把它添加到了index.html里利诺。
因?yàn)樘砑拥絠ndex.html之后,我的pushHistory()將變成全局可以調(diào)用的方法剩燥,因?yàn)閂ue會(huì)將所有的.vue文件渲染到這個(gè)index.html中慢逾。
我使用 window.location.hash替換掉了#,這樣以保證Router生成的hash不被破壞掉灭红。
該js代碼添加的位置一定要在head中侣滩,否則根據(jù)執(zhí)行順序,如果寫到了body后面变擒,Vue是調(diào)取不到的君珠。
2. 要有一個(gè)方法,可以在Vue的任何頁面中調(diào)用,以用于攔截window.onpopstate請(qǐng)求娇斑,并且動(dòng)態(tài)執(zhí)行我們要執(zhí)行的方法策添。
要實(shí)現(xiàn)一個(gè)在Vue個(gè)頁面中可以調(diào)用的方法很簡(jiǎn)單,我們只要寫帶main.js中悠菜,再將它掛到原型鏈上即可。
代碼如下:
function gotoURL(callback){
window.onpopstate = null;
window.onpopstate = function(){
callback()
}
}
Vue.prototype.gotoURL = gotoURL
main.js如圖
請(qǐng)只看紅框內(nèi)的代碼败富,不要在意別的悔醋。
3、調(diào)用
注意:請(qǐng)不要在App.vue中調(diào)用兽叮,因?yàn)锳pp.vue只是其它頁面的容器芬骄,只會(huì)被一次渲染, 我們?cè)谂渲肦outer的時(shí)候,一般路徑為'/'的頁面會(huì)被直接渲染到App.vue中鹦聪,所以當(dāng)我們要控制初始頁面的返回鍵账阻,需要找到對(duì)應(yīng)的vue文件中調(diào)用方法,而不是在App.vue中調(diào)用方法泽本。
調(diào)用一般為 一個(gè)頁面一次性調(diào)用淘太,意思就是在頁面渲染的時(shí)候,我們就要調(diào)用這個(gè)方法规丽。
所以我要(建議)將調(diào)用的方法寫到mounted周期中蒲牧。如下:
mounted() {
let that =this;
pushHistory() // 必須存在
that.gotoURL(function () {
pushHistory() // 必須存在
console.log('666') // 點(diǎn)擊返回鍵要執(zhí)行的方法
})
}
為什么要把pushHistory調(diào)用兩次?
我也曾刪掉它們之中的任何一個(gè)赌莺,但是會(huì)出現(xiàn)返回鍵無法正潮溃控制的問題,所以先加上艘狭,后期如果有更好方法挎扰,我會(huì)發(fā)上來翠订。
不要濫用這個(gè)方法,只在需要的頁面中使用遵倦,不需要的頁面中請(qǐng)不要調(diào)用尽超,以防出現(xiàn)問題。
產(chǎn)品設(shè)計(jì)建議: PM在設(shè)計(jì)產(chǎn)品時(shí)骇吭,請(qǐng)要考慮移動(dòng)端的一些問題橙弱,盡量避免硬核控制返回鍵的情況出現(xiàn)。
如果讀者有其它需要燥狰,可以通過我的簡(jiǎn)書首頁簽名下方的微信二維碼添加我好友棘脐,請(qǐng)注明來意。
補(bǔ):
有的朋友問我為什么使用DOM0事件控制popstate而不是DOM2,因?yàn)镈OM2無法解綁匿名函數(shù)龙致,因?yàn)槲以诓煌撁娲M(jìn)來的callback是不一樣的蛀缝。使用DOM2會(huì)出現(xiàn)事件疊加。根據(jù)事件機(jī)制目代,所以使用DOM0屈梁,讓每一次的事件都替換上一次的事件。
而在傳統(tǒng)的JS中為什么可以使用DOM2榛了,是因?yàn)槊恳粋€(gè)頁面都切換了運(yùn)行環(huán)境在讶,所以前一個(gè)頁面的DOM2不會(huì)和當(dāng)前頁面的DOM2相疊加。