編程式導航
1 .用在可復用的路由視圖里面趣竣,比如所有的需要跳轉到一個文章具體內容的路由辖源,每一次跳轉到新路由的時候输枯,其實傳的東西都是這個文章的id,在里面再次進行請求嚼贡,別的東西都是一樣的,還有就是在這個情況下返回娘扩。
2 .本質就是監(jiān)聽URL的變化着茸,然后匹配路由規(guī)則,顯示相應的頁面琐旁,而且無需刷新涮阔。
代碼實現(xiàn)方面
哈希路由
1 .通過location.hash獲取到網址#號后面的網頁位置標識符
2 .onhashchange事件來監(jiān)聽哈希的變化然后執(zhí)行響應的回調函數(shù)
3 .不同的#值,表示不同的訪問狀態(tài)灰殴,向用戶發(fā)出某個狀態(tài)的訪問鏈接,也就是說用所有的哈希值來索引到具體顯示的某一個頁面
4 .代碼
// 對window事件進行包裝和兼容
// 兩種思路吧敬特,一種就是直接使用next,pre這樣的指針來指定,一種就是把所有的操作都放到一個棧里面验懊。
const addEvent=(function(){
if(window.addEventListener){
return function(ele,event,handle,isBuble){
isBuble=isBuble||false
ele.addEventListener(event,handle,isBuble)
}
}else if(window.attachEvent){
return function(ele,event,handle){
ele.attachEvent('on'+event,handle)
}
}else{
return function(ele,event,handle){
return function(ele,event,handle){
ele['on'+event]=handle
}
}
}
})()
class Router{
constructor(){
// this.routers={}
// this.pre=this.pre||null
// this.next=this.next||null
// 不是必須
// 也就是說當定義一個和系統(tǒng)api相關的類的時候擅羞,
this.currentUrl=null
this.currentIndex=null
this.routerArr=[]
this.len=0
this.canpush=true
//一個是否記錄的開關,現(xiàn)在就是go义图,和back的所有操作都不會記錄减俏,只會記錄點擊的歷史記錄,就是因為如果要記錄go碱工,和back的操作的話娃承,可能會造成死循環(huán)。
window.addEventListener('load',()=>{
this.updateUrl()
})
// 這個是關鍵怕篷。這個類需要檢測的東西也可以加在這里么历筝?
//constructor里面竟然也可以加這個東西,真的奇怪廊谓,類這個東西還得探索一下其他的功能
window.addEventListener('hashchange',()=>{
if(this.canpush){
this.updateUrl()
}else{
console.log('')
}
})
}
// 初始化route梳猪,以及更新路由
updateUrl(){
this.currentUrl=window.location.hash.slice(1)||'/'
this.routerArr.push(this.currentUrl)
this.len=this.routerArr.length
this.currentIndex=this.routerArr.length-1
this.canpush=true
}
back(){
console.log('back')
console.log(this)
this.canpush=false
if(this.currentIndex==0){
window.location.hash='#'+this.routerArr[this.len-1]
this.currentIndex=this.len-1
}else{
window.location.hash='#'+this.routerArr[this.currentIndex-1]
this.currentIndex--
}
}
go(){
// 還需要計算下沒有進行記錄的時候做了前進點擊
console.log('go')
console.log(this)
this.canpush=false
if(this.currentIndex==this.len-1){
window.location.hash='#'+this.routerArr[0]
this.currentIndex=0
}else{
window.location.hash='#'+this.routerArr[this.currentIndex+1]
this.currentIndex++
}
}
}
5 .但是這個只能做一些前后倒退的簡單操作,想要一一對應起來蒸痹,的需要key-value形式的數(shù)據結構
6 .或者是最后渲染出來的頁面春弥,真正自己構造路由的時候還是想要上面那種結果呛哟,感覺這個適合服務端渲染,每一個或者每一種情況渲染出來的頁面對應著唯一的哈希url
7 .升級改造的話匿沛,其實數(shù)組里面應該是這樣的,記錄頁面的訪問次數(shù)扫责,訪問順序。
{
hash:'/',
count:1
}
history路由
1 .缺點:pushState逃呼,replaceState只會對url進行改變鳖孤,不會觸發(fā)頁面刷新,只是導致history對象發(fā)生變化抡笼,不能跨域苏揣。這就導致如果直接輸入url,但是后端沒有處理的話蔫缸,直接是404腿准,哈希路由可以定位到某個具體的dom
2 .代碼
3 .怎么樣升級下既能用上哈希的準確性,有可以方便使用的時候傳入key-value的一個地址對應組件的操作
4 .點擊一個地址的時候拾碌,現(xiàn)在我傳入的數(shù)組里面找我是否定義了這個地址對應的組件,如果沒有街望,可以選擇定義新的地址然后加入校翔,也可以彈出報錯,把這個加入
5 .還是想做的就是go.back不記錄到歷史記錄里面灾前。
6 .整個思路其實是這樣的防症,router-link之類的標簽點擊觸發(fā)的時候,先在router傳入的對象里面去尋找哎甲,是否有對應的組件來展示對應的路由地址
7 .那其實這個升級版的路由其實有兩個功能蔫敲,一個是存儲歷史記錄,一個是顯示對應的組件炭玫,上一個路由組件需要存儲功能我們交給了history API奈嘿,但是這個api是不會保存和組件有關的操作,所以我們需要把和組件有關的歷史記錄人為的添加到這個api里面
8 .代碼
window.history的簡單方法
1 .history.length:當前窗口訪問過網址的數(shù)量
2 .history.state:history堆棧最上層的狀態(tài)值
3 .history.back():前一個網址
4 .history.forward():移動到下一個網址吞加。
5 .history.go(n):以當前網址為基準裙犹,進行移動。正數(shù)為前衔憨,負數(shù)為后叶圃。0的話相當于刷新當前頁面。
6 .window.history.pushState(state,title,url)
7 .最后一個url必須是同一域名的url践图,不然會認為是有安全隱患
8 .pushState是不會觸發(fā)刷新頁面掺冠,只是導致history對象發(fā)生變化,地址欄會有反應
9 .history.replaceState()修改當前history的記錄码党,參數(shù)和上個函數(shù)的一樣
10 .特殊事件:popstate,用戶點擊前進德崭,后退按鈕悍及,或者使用js調用History.back(),History.go(),History.forward()方法才會觸發(fā),而且這個事件只針對同一個文檔接癌,如果瀏覽歷史發(fā)生了改變心赶,導致加載了不同的文檔,事件也不會觸發(fā)缺猛,事件的回調參數(shù)就是以上兩個方法傳入的第一個參數(shù)缨叫。
window.onpopstate = function (event) {
console.log('location: ' + document.location);
console.log('state: ' + JSON.stringify(event.state));
};
// 或者
window.addEventListener('popstate', function(event) {
console.log('location: ' + document.location);
console.log('state: ' + JSON.stringify(event.state));
});
組件源碼分析
Vue.use
1 .在Vue路由里面增加覆蓋所有情況的候選資源,如果url匹配不到任何資源荔燎,返回一個404頁面
2 .使用方法:每一個路由映射一個組件
3 .Vue.use(router):將組件插入到Vue中去耻姥,use方法會檢測組件內是否有install方法,如果有的話有咨,執(zhí)行install方法
4 .對于路由注冊來說琐簇,核心就是調用Vue.use(vueRouter),使VueRouter可以調用Vue,然后通過Vue來調用VueRouter的install函數(shù)座享,在該函數(shù)中婉商,核心就是給組件混入鉤子函數(shù)和全局注冊兩個路由組件
5 .全局混合方法來初始化VueRouter
6 .給當下所有組件注入route對象
install
1 .對插入組件在beforecreate鉤子操作,在Vue聲明周期階段就可以調用到組件的相關方法
2 .通過Vue.prototype定義router,route屬性渣叛,這樣所有的組件都可以獲取到這兩個屬性
3 .Vue上注冊router-link,router-view組件
生成router實例
1 .根據配置數(shù)組生成路由配置記錄表
2 .根據不同的模式生成監(jiān)控路由變化的History對象
3 .創(chuàng)建一個路由匹配對象丈秩,根據mode來踩去不同的路由方式
生成Vue實例
1 .把router傳入new Vue()中
2 .進入Vue的生命周期,執(zhí)行第一步router對Vue混入beforeCreate鉤子函數(shù)淳衙,判斷實例化的options是否包含routr-為組件的router-view組件渲染提供$route蘑秽,保證router.init只被調用一次
3 .初始化結束,界面將顯示默認首頁
4 .當根組件調用beforeCreate鉤子函數(shù)的時候箫攀。初始化路由肠牲,因為只有根組件會有router屬性
5 .在路由初始化的時候,核心就是i進行路由的跳轉靴跛,改變URL然后渲染對應的組件缀雳。
路由更新方式
1 .router-link綁定的click方法,觸發(fā)history.push或者history.replace汤求,從而進行路由轉換俏险,更新路由。在BeforeCreate有劫持_route方法扬绪,當_route發(fā)生變化后竖独,router-view自動變化。
2 .地址變化:HashHistory或者HTMLHistory會自動監(jiān)控hashchange和popState來對路由變化做處理挤牛,從而執(zhí)行上面那一套程序莹痢。
Vue插件機制
1 .
組件特殊方法
1 .this.route:返回當前路由
動態(tài)路由
1 .不僅僅是具體的歌曲頁面可以使用這個功能,某種模式全需要匹配到一個路由,就好像一個帶子可以把雜亂的路由全都梳理起來竞膳,只不過這個使用之后無法在每個具體的路徑下面在添加子路徑航瞭,所以這個一般才會用在最末端的路徑。
2 ./user/:username/post/:post_id 他是可以分段約束的坦辟。這樣有更大的靈活性刊侯。這樣上面那個問題應該可以解決了。那這個可以隨便用了锉走,只不過還是需要一些約束滨彻,可以看下別人路由是如何設計的
3 .可以變化的那些路徑參數(shù)都是可以在this.$router.params里面訪問到,這個如果是漢字的路徑參數(shù)的話挪蹭,是可以直接在組件里面顯示的亭饵,但是如果是英文的話,還需要一個映射表梁厉。
4 .這個還是有局限性辜羊,雖然路徑是可以類似的正則匹配到,但是組件是只能對應一個的词顾。所以還是還是需要拆開八秃。他適用的是一套模板但是對應不同數(shù)據的情況,轉到對應的界面之前计技,把請求的資源的標記存到vuex里面喜德,到了這個組件里面開始ajax請求,填充頁面內容垮媒。
5 .這樣又出現(xiàn)個問題,路由參數(shù)變化的時候航棱,對應組件勢力會被復用睡雇,比起銷毀在創(chuàng)建,復用更加高效饮醇。此時組件的生命周期是不會被調用的它抱,那么mounted里面定義的函數(shù)可能不會初始化,所以需要watch監(jiān)視下路由參數(shù)的響應朴艰,一旦發(fā)生變化观蓄,而且符合變化的條件,那就進行初始化祠墅。
6 .匹配優(yōu)先級是按照定義的位置順序來算的侮穿,先到先匹配
編程式導航
1 .this.$router.push('home') 它實現(xiàn)的效果和router-link實現(xiàn)的方式一樣。
2 .適用場景:返回操作毁嗦,只是知道下一步要怎么操作亲茅,但是沒有具體的地址,或者在頁面上不方便表現(xiàn)出來操作的UI,就需要在底層使用編程導航
3 .編程式導航的語法完全類似于window.history語法
4 .
命名路由
1 .在index里面給特殊的路由加上name克锣,這樣在跳轉的時候就會很方便茵肃,比如跳轉到首頁以及重定向的時候。
2 .一張頁面需要顯示多個路由窗口的時候袭祟。類似iframe的效果
3 .這個時候使用編程式導航的時候傳參數(shù)的時候非常方便
4 .鏈接的時候傳的是數(shù)組验残,里面有name關鍵字一般的傳的是path
5 .編程式導航的時候也是push這樣的數(shù)組參數(shù)
6 .
命名視圖
1 .components:{default:}默認參數(shù)
2 .router-view 里面有name屬性。
3 .components:里面?zhèn)魅雽慕M件數(shù)組 name:組件名
重定向巾乳,別名
1 .redirect:訪問當前路由地址的時候您没,重定向到另一個路由地址下的視圖
2 .alais:給任意一個路由加一個這參數(shù),起個名字想鹰,然后直接router-link 的to就可以過來
3 .那別名和命名路由的區(qū)別是什么紊婉?看理論感覺用法差不多,還是實踐下看看差距在哪里吧辑舷。
重要api
router-link
1 .無論是HTML history模式還是hash模式喻犁,行為表現(xiàn)一致。切換路由模式的時候何缓,無需做任何的改動
2 .在html history模式下肢础,roter-link會令守衛(wèi)點擊事件,讓瀏覽器不在加載頁面
3 .在hisitory下使用base選項之后碌廓,所有的to屬性都不需要寫(基路徑)了传轰。
4 .to:當路由目標被點擊后,會立刻把to的值傳到router.push()谷婆,這個值可以是一個字符串或者描述目標位置的對象,那這樣我們在寫組件的時候其實可以是任意一個值慨蛙,只要他有to這個傳入屬性,那么就可以點擊觸發(fā)router.push函數(shù)進行路由轉換
1 .可以使用v-bind:傳入動態(tài)參數(shù)纪挎,比如動態(tài)渲染一個樹形導航
2 .傳入對象的時候期贫,可以是path,name,path+query
5 .replace參數(shù):設置replace的話,點擊的對象异袄,進行跳轉的時候不記錄歷史記錄
6 .append:相對于傳入的路徑前面添加一個基路徑通砍,這個基路徑是什么?
7 .tag:‘router-link渲染出什么結果’烤蜕,默認是a標簽
8 .router-link-active:選中的時候自動給標簽價加上這個樣式封孙,你可以把想定義的樣式放在這個里面
9 .event:觸發(fā)的事件,默認是click
10 .exact:這個看文檔看不懂讽营。
11 .exact-active-class:
router-view
1 .因為他也是個組件虎忌,所以可以配合transition,keepalive使用斑匪,如果兩個一起使用呐籽,確保內層使用keep-alive
2 .name:router-view設置了名稱锋勺,則會渲染對應路由配置中conponents中下的對應組件
index.js文件里面
routes
1 .path
2 .components
3 .component
4 .redirect
5 .alias
6 .props
7 .children
8 .meta
9 .beforeEnter
10 .caseSencetive:是否對匹配規(guī)則大小敏感
11 .pathToregexOptions:object編譯匹配正則的選項
mode
1 .hash:使用URL hash值來做路由,支持所有瀏覽器
2 .history:依賴HTML History和服務器配置狡蝶。需要后臺支持庶橱,如果后臺沒有配置對應的路由,就會返回404贪惹,所以必須增加一個能夠覆蓋所有情況的候選資源苏章,如果url匹配不到任何靜態(tài)資源,返回一個默認的頁面奏瞬。這個需要前端和后端來把保證對url資源的共同配置枫绅。