路由概念
路由這一概念最早出現(xiàn)在后端(即后端渲染),前端是沒有的巍扛。
它經(jīng)歷了三個階段的演進:由后端路由(讓服務器去處理)到前后端分離的開發(fā)模式(也就是Ajax的出現(xiàn)),再到單頁面富應用階段(Simple Page web Application,即SPA)
目前前端流行的三大框架熔萧,都有自己的路由實現(xiàn):
- Angular的ngRouter
- React的ReactRouter
- Vue的vue-router(是官方的路由插件假褪,它和vue.js是深度集成的,適合用于構(gòu)建單頁面應用)
vue-router是基于路由和組件的
- 路由用于設定訪問路徑杂抽,將路徑和組件映射起來
- 在vue-router的單頁面應用中,頁面的路徑的改變就是組件的切換
Vue前端路由的核心:
- 改變URL韩脏,但整體頁面不再進行刷新缩麸,區(qū)別于H5的a標簽。
而我們常見的大多數(shù)網(wǎng)站赡矢,當改變URL的時候杭朱,都會向服務器發(fā)送請求數(shù)據(jù)阅仔,然后再渲染到頁面上,這一過程會導致頁面重新加載刷新弧械,而使用前端路由實現(xiàn)則不會如此八酒。
Vue實現(xiàn)前端路由的兩種方式:
- URL的hash,即我們通常稱哈希模式(#)。
- H5的history模式:pushState | replaceState | go | back
哈希模式:location.hash="path"
URL中的hash
- URL中的hash也就是錨點(#)刃唐,本質(zhì)上是改變window.location的href屬性(hype reference,超鏈接引用)
- 通過直接賦值location.hash來改變href,致使頁面不會發(fā)送刷新
history模式(棧結(jié)構(gòu))
- 棧結(jié)構(gòu)就像一個彈夾羞迷,最新進棧都會被壓在棧底,
- 原理是先進后出画饥,出棧只能先從棧頂往下衔瓮,然后拿東西,
- 隊列是先進先出抖甘。
history.pushState({}, '', 'paht'),即入棧模式
history.back()返回上一層的頁面(類似返回上一次的歷史記錄热鞍,即出棧模式)。
history.replaceState()替換模式
替換模式不是壓入棧衔彻,此外薇宠,返回按鈕也不能用。
小結(jié):
- history.back()等價于 history.go(-1)
- history.forward()等價于 history.go(1)
- 這兩個接口等同于瀏覽器界面上的前進后退按鈕
安裝路由
如果在腳手架創(chuàng)建模板的時候艰额,沒有勾選配置路由澄港,現(xiàn)在是可以通過npm進行安裝的。
-
使用Vue CLI2版本配置的路由悴晰,出現(xiàn)在src源碼目錄下慢睡。
為了幫助我們更好地加深認知router,直接刪除改文件夾,自己手動配置路由铡溪。
Vue CLI2腳手架手動配置路由具體步驟如下:
-
在src源碼目錄下創(chuàng)建一個名叫router的文件夾漂辐,在該文件夾(router)下創(chuàng)建一個index.js的腳本文件,在index.js這個腳本文件里面配置路由相關(guān)的信息棕硫。
-
index.js文件配置路由相關(guān)信息詳情:
-
在main.js入口文件進行導入操作使用髓涯。
- 到這里,路由的框架已經(jīng)具備搭建好了哈扮,現(xiàn)在只差配置路由的映射關(guān)系纬纪。
為了保持整潔的頁面,將腳手架默認創(chuàng)建的組件刪掉(即Hello World.vue文件)滑肉,保持一個空的components目錄即可包各。
清除App.vue的模板內(nèi)容,保持整潔靶庙。
在components目錄下創(chuàng)建一個About.vue組件和一個Home.vue組件问畅。
內(nèi)容如下:
-
在index.js里面配置路徑的映射關(guān)系。
-
一個對象是一個映射關(guān)系。
-
來到根組件App.vue配置路由模板护姆,router-link是vue-router自己注冊的組件矾端,他們是全局組件,可以在任何位置使用卵皂。
-
頁面url效果秩铆,類似h5的a標簽,其實最終渲染的也是a標簽灯变。
控制臺查看發(fā)現(xiàn)是個a標簽 -
路由默認值的設置殴玛,給用戶第一視角,進來的時候就顯示出整個網(wǎng)站的首頁柒凉。
糾錯:重定向路由這里應該是redirect: 'Home',少了引號族阅。
-
將默認的哈希hash模式改為history模式,因為hash模式自帶#號作為默認膝捞,看起來有點別扭坦刀。
-
router-view 決定組件渲染的位置,它實現(xiàn)的效果是占位蔬咬。
-
router-view切換組件效果
router-link屬性
- 屬性to :用于跳轉(zhuǎn)指定的路徑鲤遥。
- 屬性tag: 默認渲染成a標簽,如果想使用其他標簽林艘。通過tag屬性綁定h5標簽使用盖奈。
-
屬性replace: 只允許在頁面切換,不能使用瀏覽器的返回按鈕狐援。
要重新打開8080端口钢坦,才能看到實際效果。
屬性replace會自帶一個class樣式的活躍狀態(tài)類啥酱。
有了它爹凹,我們可以寫樣式效果。
- active-class屬性:用于修改默認的router-link-active樣式镶殷,一般在進行高亮導航菜單或者底部的tabbar時禾酱,會用到該類。
-
linkActiveClass屬性:統(tǒng)一修改樣式绘趋,只不過颤陶,它不再是router-link的屬性了,而是屬于router對象實例屬性了陷遮。
我們來到index.js
路由代碼實現(xiàn)跳轉(zhuǎn)方式
-
有時候滓走,頁面的跳轉(zhuǎn)可能需要執(zhí)行對應的JS代碼,這個時候帽馋,就可以使用第二種跳轉(zhuǎn)方式了搅方。
但不能點擊自身(首頁)超過2次否則會報錯疫粥,首頁和分頁輪流切換不會報錯。
使用replace可以解決腰懂。
Vue動態(tài)路由
- 上面設置的路由都是靜態(tài)路由。
- 在某些情況下项秉,一個頁面的path路徑可能時不確定的绣溜,比如我們進入用戶界面時,希望是如下這種路徑/user/zhangsan或者是/user/lisi
- 除了有前面的/user之外娄蔼,我們通常會見到某些網(wǎng)站后面還跟上了對應的id號怖喻。
- 這種path和component的匹配關(guān)系,我們稱之為動態(tài)路由岁诉,它也是路由傳遞數(shù)據(jù)的一種方式锚沸。
代碼試圖:
-
創(chuàng)建一個User.vue組件。
-
在index.js里面配置組件的映射關(guān)系涕癣。
-
在App.vue組件里面實現(xiàn)動態(tài)綁定路由哗蜈。
-
需求:在User.vue組件獲取當前用戶界面的信息。
路由懶加載方案
- 當我們通過npm run build打包構(gòu)建應用的時候坠韩,js包會變得非常巨大距潘,會影響頁面的加載進程效果。
- 為什么會這樣只搁?
因為音比,我們知道路由中通常會定義了很多不同的頁面組件,這個頁面最后會被打包放在一個js文件中氢惋,但是這么多頁面組件被壓擠在一個js文件中洞翩,必然會造成這個頁面非常的龐大。
如果我們一次性從服務器請求下這個頁面焰望,可能需要花費一定的時間骚亿,甚至導致用戶的瀏覽器出現(xiàn)了短暫的空白情況,用戶體驗十分不好柿估。 - 我們能否避免這種頁面短暫空白的情況呢循未?
官方給出了解釋:使用路由懶加載方案可以實現(xiàn),如果我們能把不同路由對應的組件分割成不同的代碼塊進行處理秫舌,然后當路由被訪問的時候加載對應的組件的妖,這樣就變得更加的高效了。 -
路由懶加載到底做了什么足陨?
路由懶加載的主要作用就是將對應的組件打包成一個個的js代碼塊嫂粟。
只有在這個路由被訪問到的時候,才開始加載對應的組件墨缘。
打包js文件的解析
路由懶加載的方式(三種)
早期出現(xiàn)2種星虹,一種使用的是異步解決方案零抬,另一種是AMD寫法,了解即可宽涌。
-
方式三:ES6方案平夜,在ES6中,我們可以用更加簡潔的寫法(箭頭函數(shù))來組織Vue異步組件和Webpack的代碼分割卸亮。
-
為了使用路由懶加載模式忽妒,我們需要在index.js里面進行代碼重構(gòu)。
-
通過npm run build 打包后兼贸。
嵌套路由
-
嵌套路由是一個非常常見的功能段直,比如我們想在home(首頁)中繼續(xù)進行細分頁面的時候就會應用到了嵌套路由了,我們希望通過home首頁訪問new頁面(即/home/new)或者通過/home/detail訪問一些內(nèi)容溶诞。
一個路徑映射一個組件鸯檬,因此,訪問這兩個路徑也會分別渲染2個組件螺垢。
image.png - 路徑和對應組件的關(guān)系如下:
實現(xiàn)嵌套路由步驟: -
創(chuàng)建對應的子組件喧务,填寫簡潔模板即可。
- 在index.js中配置路由映射甩苛,并且是配置對應的子路由(這里我們配置的是home首頁的子路由)蹂楣,使用到children(子路由)數(shù)組可以包含多個對象。
路由懶加載配置
children配置子路由
-
在組件內(nèi)部使用占位標簽<router-view>,因為我們的新聞頁面(news)和詳情頁(details)是在首頁里面配置子路由的讯蒲,所以我們是在home頁里面使用占位標簽<router-view>進行顯示痊土。
但當我們點擊其他頁面,然后再回來點擊首頁墨林,發(fā)現(xiàn)我們點擊原來子路由的(新聞頁面)時赁酝,新聞頁面的內(nèi)容消失了,而我們希望是默認顯示新聞頁面的旭等。
所以我們需要在子路由下面進行重定向酌呆,默認顯示news頁面。
路由的參數(shù)傳遞搔耕,傳遞參數(shù)主要有2種類型:分別是params和query
params的類型
-
配置路由格式(index.js): /router/:id
-
傳遞的方式(App.vue):在path后面跟上對應的值
- 傳遞后形成的路徑(User.vue):/router/id
-
從Profile.vue中取App.vue的值隙袁。
query的類型
- 配置路由格式:/router,也就是普通配置路由即可。
創(chuàng)建Profile.vue組件弃榨。
index.js文件中菩收,進行路由懶加載配置。
普通路由映射配置鲸睛。
-
傳遞的方式(App.vue中):對象中使用query的key作為傳遞方式
-
傳遞后形成的路徑:/router?id=123, /router?id=abc
-
從Profile.vue中取App.vue的值娜饵。
路由代碼實現(xiàn)路由參數(shù)跳轉(zhuǎn)方式
-
定義2個按鈕,綁定相對應的路由點擊事件官辈。
全局導航守衛(wèi)
全局導航守衛(wèi)是個啥?
- vue-router提供的導航守衛(wèi)主要用來監(jiān)聽路由的進入和離開的箱舞。
- vue-router提供了beforeEach前置守衛(wèi)(guard)鉤子(hook)函數(shù)和afterEach的后置導航鉤子函數(shù)(路由跳轉(zhuǎn)完后實現(xiàn)回調(diào)機制)遍坟,他們會在路由即將改變前和改變后觸發(fā)。
- 簡單點就是想監(jiān)聽路由來回跳轉(zhuǎn)的過程晴股,獲取路由跳轉(zhuǎn)到哪個位置愿伴,然后在監(jiān)聽函數(shù)里面搞事情。
全局導航守衛(wèi)實際效果是啥电湘?
-
就是想實現(xiàn)我們的網(wǎng)頁置頂title標簽
- 當我們點擊首頁的時候公般,title變成首頁,點擊用戶頁面的時候胡桨,title變成用戶,有點類似小程序和app頭頂上的NavigationBar導航,點擊了哪個導航瞬雹,就顯示對應的title昧谊。
怎么實現(xiàn)上述效果呢?
給每個對應的參與路由跳轉(zhuǎn)的組件添加生命周期鉤子函數(shù)酗捌,created.
我們來看下title的效果:
小結(jié):
- 我們上面采用的是比較普通的實現(xiàn)方式呢诬,我們會想到其實修改標題的位置就是每一個路由對應的.vue組件文件。
-通過created生命周期函數(shù)胖缤,執(zhí)行對應的代碼進行修改即可 - 雖然效果可實現(xiàn)了尚镰,但一個個去修改顯然有點唐突+狼狽了(幾百個頁面的時候就顯然不合適這樣的操作去維護)。
導航守衛(wèi)的使用
- 真正的全局守衛(wèi)導航是在router/index.js里面配置的哪廓。
-
我們首先拿到router對象狗唉,這個router對象里面有一個beforeEach()方法,這個beforeEach()方法里面有三個參數(shù)涡真,分別是to, from, next
- 我們可以利用beforeEach來完成對導航標題的修改分俯。
- 我們可以在鉤子當中用meta來定義一些標題。
- 其次呢哆料,利用導航守衛(wèi)修改我們的標題缸剪。
beforeEach導航鉤子三個參數(shù)的解釋:
- to: 即將進入的目標路由對象。
- from: 當前導航即將要離開的路由對象东亦。
- next: 調(diào)用該方法后杏节,才能進入下一個鉤子,不調(diào)用一下next()方法的話典阵,整個頁面的路由跳轉(zhuǎn)將會被攔截,next方法告訴瀏覽器下一步要干嘛奋渔,千萬別給我攔截了。
- 大概就是從from跳轉(zhuǎn)到to
顯然我們不能拿到to.title這樣一個的數(shù)據(jù)
-
所以要在組件映射里面添加每個對應的meta屬性(元數(shù)據(jù):描述數(shù)據(jù)的數(shù)據(jù))
這樣全局導航守衛(wèi)效果總體就實現(xiàn)了萄喳,但還有一點瑕疵卒稳,就是當我們點擊首頁的時候,title變成了undefine他巨。
為什么會這樣充坑?
這和我們在首頁里面使用了嵌套子路由有關(guān)系减江。
我們嘗試打印to對象看下。
所以我們只要找到matched(匹配)的0號位捻爷,就能解決子路由這塊的小bug
如果是后置鉤子函數(shù)辈灼,即afterEach,不需要主動調(diào)用next()函數(shù)也榄。
- 上面我們使用的導航守衛(wèi)巡莹,叫做全局守衛(wèi)
- 此外還有路由獨享的守衛(wèi)、組件內(nèi)的守衛(wèi)甜紫。
keep-alive遇上vue-router
keep-alive可以保留組件內(nèi)部切換回來的顯示之前用戶的瀏覽狀態(tài)降宅。
比如我們當前在首頁,點擊了新聞詳情頁面子路由囚霸,然后去點擊了檔案腰根,現(xiàn)在再回去點擊首頁,發(fā)現(xiàn)它停留在了新聞頁面拓型,而不是我們想回去剛剛瀏覽過的新聞詳情頁面额嘿,遇到這種狀況的話,就要使用keep-alive去解決了劣挫。
那為什么會出現(xiàn)這樣的情況呢册养?
我們用生命周期函數(shù)測試下就明白了。
我們可以看到压固,當我們點擊首頁的時候煞烫,組件被創(chuàng)建生成悍汛,點擊其他頁面的時候,組件已經(jīng)銷毀了,如此一直循環(huán)下去祝沸,默認顯示的都是新聞頁面来涨,而不是新聞詳情頁面濒蒋。
keep-alive(保持組件活著)概念理解嗤练,結(jié)合代碼解決上面提出的問題。
- keep-alive是Vue內(nèi)置的一個組件矿咕,可以使被包含的組件保留狀態(tài)抢肛,或避免重新渲染。
keep-alive有2個重要屬性 -
include - 字符串或正則表達碳柱,只有匹配的組件會被緩存捡絮。
-exclude - 字符串或正則表達,任何匹配的組件都不會被緩存莲镣。
-
router-view也是一個組件福稳,如果直接被包在keep-alive里面,所以路徑匹配到的試圖組件都會被緩存瑞侮。
我們還要注銷掉首頁下的圆,默認新聞頁面內(nèi)容展示鼓拧。
我們需要用到組件內(nèi)的守衛(wèi)知識:beforeRouteLeave
官網(wǎng):https://router.vuejs.org/zh/guide/advanced/navigation-guards.html