Vue router前端路由筆記

路由概念

路由這一概念最早出現(xiàn)在后端(即后端渲染),前端是沒(méi)有的。

它經(jīng)歷了三個(gè)階段的演進(jìn):由后端路由(讓服務(wù)器去處理)到前后端分離的開(kāi)發(fā)模式(也就是Ajax的出現(xiàn)),再到單頁(yè)面富應(yīng)用階段(Simple Page web Application,即SPA)


目前前端流行的三大框架,都有自己的路由實(shí)現(xiàn):
  • Angular的ngRouter
  • React的ReactRouter
  • Vue的vue-router(是官方的路由插件,它和vue.js是深度集成的,適合用于構(gòu)建單頁(yè)面應(yīng)用)
vue-router是基于路由和組件的
  • 路由用于設(shè)定訪問(wèn)路徑,將路徑和組件映射起來(lái)
  • 在vue-router的單頁(yè)面應(yīng)用中,頁(yè)面的路徑的改變就是組件的切換
Vue前端路由的核心:
  • 改變URL,但整體頁(yè)面不再進(jìn)行刷新,區(qū)別于H5的a標(biāo)簽。

而我們常見(jiàn)的大多數(shù)網(wǎng)站,當(dāng)改變URL的時(shí)候,都會(huì)向服務(wù)器發(fā)送請(qǐng)求數(shù)據(jù),然后再渲染到頁(yè)面上,這一過(guò)程會(huì)導(dǎo)致頁(yè)面重新加載刷新,而使用前端路由實(shí)現(xiàn)則不會(huì)如此。

Vue實(shí)現(xiàn)前端路由的兩種方式:
  • URL的hash,即我們通常稱(chēng)哈希模式(#)。
  • H5的history模式:pushState | replaceState | go | back
哈希模式:location.hash="path"
URL中的hash
  • URL中的hash也就是錨點(diǎn)(#),本質(zhì)上是改變window.location的href屬性(hype reference,超鏈接引用)
  • 通過(guò)直接賦值location.hash來(lái)改變href,致使頁(yè)面不會(huì)發(fā)送刷新
history模式(棧結(jié)構(gòu))
  • 棧結(jié)構(gòu)就像一個(gè)彈夾,最新進(jìn)棧都會(huì)被壓在棧底,
  • 原理是先進(jìn)后出,出棧只能先從棧頂往下,然后拿東西,
  • 隊(duì)列是先進(jìn)先出。
history.pushState({}, '', 'paht'),即入棧模式

history.back()返回上一層的頁(yè)面(類(lèi)似返回上一次的歷史記錄,即出棧模式)。
history.replaceState()替換模式

替換模式不是壓入棧,此外,返回按鈕也不能用。






小結(jié):
  • history.back()等價(jià)于 history.go(-1)
  • history.forward()等價(jià)于 history.go(1)
  • 這兩個(gè)接口等同于瀏覽器界面上的前進(jìn)后退按鈕
安裝路由
  • 如果在腳手架創(chuàng)建模板的時(shí)候,沒(méi)有勾選配置路由,現(xiàn)在是可以通過(guò)npm進(jìn)行安裝的。

  • 使用Vue CLI2版本配置的路由,出現(xiàn)在src源碼目錄下。


  • 為了幫助我們更好地加深認(rèn)知router,直接刪除改文件夾,自己手動(dòng)配置路由。

Vue CLI2腳手架手動(dòng)配置路由具體步驟如下:
  • 在src源碼目錄下創(chuàng)建一個(gè)名叫router的文件夾,在該文件夾(router)下創(chuàng)建一個(gè)index.js的腳本文件,在index.js這個(gè)腳本文件里面配置路由相關(guān)的信息。


  • index.js文件配置路由相關(guān)信息詳情:


  • 在main.js入口文件進(jìn)行導(dǎo)入操作使用。


  • 到這里,路由的框架已經(jīng)具備搭建好了,現(xiàn)在只差配置路由的映射關(guān)系。

為了保持整潔的頁(yè)面,將腳手架默認(rèn)創(chuàng)建的組件刪掉(即Hello World.vue文件),保持一個(gè)空的components目錄即可。

清除App.vue的模板內(nèi)容,保持整潔。



在components目錄下創(chuàng)建一個(gè)About.vue組件和一個(gè)Home.vue組件。



內(nèi)容如下:
  • 在index.js里面配置路徑的映射關(guān)系。


  • 一個(gè)對(duì)象是一個(gè)映射關(guān)系。



  • 來(lái)到根組件App.vue配置路由模板,router-link是vue-router自己注冊(cè)的組件,他們是全局組件,可以在任何位置使用。


  • 頁(yè)面url效果,類(lèi)似h5的a標(biāo)簽,其實(shí)最終渲染的也是a標(biāo)簽。



    控制臺(tái)查看發(fā)現(xiàn)是個(gè)a標(biāo)簽
  • 路由默認(rèn)值的設(shè)置,給用戶(hù)第一視角,進(jìn)來(lái)的時(shí)候就顯示出整個(gè)網(wǎng)站的首頁(yè)。


    糾錯(cuò):重定向路由這里應(yīng)該是redirect: 'Home',少了引號(hào)。

  • 將默認(rèn)的哈希hash模式改為history模式,因?yàn)閔ash模式自帶#號(hào)作為默認(rèn),看起來(lái)有點(diǎn)別扭。



  • router-view 決定組件渲染的位置,它實(shí)現(xiàn)的效果是占位。


  • router-view切換組件效果


router-link屬性
  • 屬性to :用于跳轉(zhuǎn)指定的路徑。
  • 屬性tag: 默認(rèn)渲染成a標(biāo)簽,如果想使用其他標(biāo)簽。通過(guò)tag屬性綁定h5標(biāo)簽使用。

  • 屬性replace: 只允許在頁(yè)面切換,不能使用瀏覽器的返回按鈕。
    要重新打開(kāi)8080端口,才能看到實(shí)際效果。



    屬性replace會(huì)自帶一個(gè)class樣式的活躍狀態(tài)類(lèi)。




    有了它,我們可以寫(xiě)樣式效果。

  • active-class屬性:用于修改默認(rèn)的router-link-active樣式,一般在進(jìn)行高亮導(dǎo)航菜單或者底部的tabbar時(shí),會(huì)用到該類(lèi)。

  • linkActiveClass屬性:統(tǒng)一修改樣式,只不過(guò),它不再是router-link的屬性了,而是屬于router對(duì)象實(shí)例屬性了。
    我們來(lái)到index.js


路由代碼實(shí)現(xiàn)跳轉(zhuǎn)方式
  • 有時(shí)候,頁(yè)面的跳轉(zhuǎn)可能需要執(zhí)行對(duì)應(yīng)的JS代碼,這個(gè)時(shí)候,就可以使用第二種跳轉(zhuǎn)方式了。



    但不能點(diǎn)擊自身(首頁(yè))超過(guò)2次否則會(huì)報(bào)錯(cuò),首頁(yè)和分頁(yè)輪流切換不會(huì)報(bào)錯(cuò)。



    使用replace可以解決。

Vue動(dòng)態(tài)路由

  • 上面設(shè)置的路由都是靜態(tài)路由。
  • 在某些情況下,一個(gè)頁(yè)面的path路徑可能時(shí)不確定的,比如我們進(jìn)入用戶(hù)界面時(shí),希望是如下這種路徑/user/zhangsan或者是/user/lisi
  • 除了有前面的/user之外,我們通常會(huì)見(jiàn)到某些網(wǎng)站后面還跟上了對(duì)應(yīng)的id號(hào)。
  • 這種path和component的匹配關(guān)系,我們稱(chēng)之為動(dòng)態(tài)路由,它也是路由傳遞數(shù)據(jù)的一種方式。

代碼試圖:

  • 創(chuàng)建一個(gè)User.vue組件。



  • 在index.js里面配置組件的映射關(guān)系。



  • 在App.vue組件里面實(shí)現(xiàn)動(dòng)態(tài)綁定路由。



  • 需求:在User.vue組件獲取當(dāng)前用戶(hù)界面的信息。




路由懶加載方案

  • 當(dāng)我們通過(guò)npm run build打包構(gòu)建應(yīng)用的時(shí)候,js包會(huì)變得非常巨大,會(huì)影響頁(yè)面的加載進(jìn)程效果。
  • 為什么會(huì)這樣?
    因?yàn)?,我們知道路由中通常?huì)定義了很多不同的頁(yè)面組件,這個(gè)頁(yè)面最后會(huì)被打包放在一個(gè)js文件中,但是這么多頁(yè)面組件被壓擠在一個(gè)js文件中,必然會(huì)造成這個(gè)頁(yè)面非常的龐大。
    如果我們一次性從服務(wù)器請(qǐng)求下這個(gè)頁(yè)面,可能需要花費(fèi)一定的時(shí)間,甚至導(dǎo)致用戶(hù)的瀏覽器出現(xiàn)了短暫的空白情況,用戶(hù)體驗(yàn)十分不好。
  • 我們能否避免這種頁(yè)面短暫空白的情況呢?
    官方給出了解釋?zhuān)菏褂寐酚蓱屑虞d方案可以實(shí)現(xiàn),如果我們能把不同路由對(duì)應(yīng)的組件分割成不同的代碼塊進(jìn)行處理,然后當(dāng)路由被訪問(wèn)的時(shí)候加載對(duì)應(yīng)的組件,這樣就變得更加的高效了。
  • 路由懶加載到底做了什么?
    路由懶加載的主要作用就是將對(duì)應(yīng)的組件打包成一個(gè)個(gè)的js代碼塊。
    只有在這個(gè)路由被訪問(wèn)到的時(shí)候,才開(kāi)始加載對(duì)應(yīng)的組件。


打包js文件的解析

路由懶加載的方式(三種)

早期出現(xiàn)2種,一種使用的是異步解決方案,另一種是AMD寫(xiě)法,了解即可。


  • 方式三:ES6方案,在ES6中,我們可以用更加簡(jiǎn)潔的寫(xiě)法(箭頭函數(shù))來(lái)組織Vue異步組件和Webpack的代碼分割。


  • 為了使用路由懶加載模式,我們需要在index.js里面進(jìn)行代碼重構(gòu)。


  • 通過(guò)npm run build 打包后。


嵌套路由

  • 嵌套路由是一個(gè)非常常見(jiàn)的功能,比如我們想在home(首頁(yè))中繼續(xù)進(jìn)行細(xì)分頁(yè)面的時(shí)候就會(huì)應(yīng)用到了嵌套路由了,我們希望通過(guò)home首頁(yè)訪問(wèn)new頁(yè)面(即/home/new)或者通過(guò)/home/detail訪問(wèn)一些內(nèi)容。
    一個(gè)路徑映射一個(gè)組件,因此,訪問(wèn)這兩個(gè)路徑也會(huì)分別渲染2個(gè)組件。


    image.png
  • 路徑和對(duì)應(yīng)組件的關(guān)系如下:

    實(shí)現(xiàn)嵌套路由步驟:
  • 創(chuàng)建對(duì)應(yīng)的子組件,填寫(xiě)簡(jiǎn)潔模板即可。



  • 在index.js中配置路由映射,并且是配置對(duì)應(yīng)的子路由(這里我們配置的是home首頁(yè)的子路由),使用到children(子路由)數(shù)組可以包含多個(gè)對(duì)象。

路由懶加載配置



children配置子路由


  • 在組件內(nèi)部使用占位標(biāo)簽<router-view>,因?yàn)槲覀兊男侣勴?yè)面(news)和詳情頁(yè)(details)是在首頁(yè)里面配置子路由的,所以我們是在home頁(yè)里面使用占位標(biāo)簽<router-view>進(jìn)行顯示。





    但當(dāng)我們點(diǎn)擊其他頁(yè)面,然后再回來(lái)點(diǎn)擊首頁(yè),發(fā)現(xiàn)我們點(diǎn)擊原來(lái)子路由的(新聞頁(yè)面)時(shí),新聞頁(yè)面的內(nèi)容消失了,而我們希望是默認(rèn)顯示新聞頁(yè)面的。


所以我們需要在子路由下面進(jìn)行重定向,默認(rèn)顯示news頁(yè)面。


路由的參數(shù)傳遞,傳遞參數(shù)主要有2種類(lèi)型:分別是params和query

params的類(lèi)型

  • 配置路由格式(index.js): /router/:id


  • 傳遞的方式(App.vue):在path后面跟上對(duì)應(yīng)的值



  • 傳遞后形成的路徑(User.vue):/router/id
  • 從Profile.vue中取App.vue的值。


query的類(lèi)型

  • 配置路由格式:/router,也就是普通配置路由即可。

創(chuàng)建Profile.vue組件。


index.js文件中,進(jìn)行路由懶加載配置。



普通路由映射配置。


  • 傳遞的方式(App.vue中):對(duì)象中使用query的key作為傳遞方式


  • 傳遞后形成的路徑:/router?id=123, /router?id=abc




  • 從Profile.vue中取App.vue的值。



路由代碼實(shí)現(xiàn)路由參數(shù)跳轉(zhuǎn)方式

  • 定義2個(gè)按鈕,綁定相對(duì)應(yīng)的路由點(diǎn)擊事件。



全局導(dǎo)航守衛(wèi)

全局導(dǎo)航守衛(wèi)是個(gè)啥?

  • vue-router提供的導(dǎo)航守衛(wèi)主要用來(lái)監(jiān)聽(tīng)路由的進(jìn)入和離開(kāi)的。
  • vue-router提供了beforeEach前置守衛(wèi)(guard)鉤子(hook)函數(shù)和afterEach的后置導(dǎo)航鉤子函數(shù)(路由跳轉(zhuǎn)完后實(shí)現(xiàn)回調(diào)機(jī)制),他們會(huì)在路由即將改變前和改變后觸發(fā)。
  • 簡(jiǎn)單點(diǎn)就是想監(jiān)聽(tīng)路由來(lái)回跳轉(zhuǎn)的過(guò)程,獲取路由跳轉(zhuǎn)到哪個(gè)位置,然后在監(jiān)聽(tīng)函數(shù)里面搞事情。

全局導(dǎo)航守衛(wèi)實(shí)際效果是啥?

  • 就是想實(shí)現(xiàn)我們的網(wǎng)頁(yè)置頂title標(biāo)簽
  • 當(dāng)我們點(diǎn)擊首頁(yè)的時(shí)候,title變成首頁(yè),點(diǎn)擊用戶(hù)頁(yè)面的時(shí)候,title變成用戶(hù),有點(diǎn)類(lèi)似小程序和app頭頂上的NavigationBar導(dǎo)航,點(diǎn)擊了哪個(gè)導(dǎo)航,就顯示對(duì)應(yīng)的title。

怎么實(shí)現(xiàn)上述效果呢?

給每個(gè)對(duì)應(yīng)的參與路由跳轉(zhuǎn)的組件添加生命周期鉤子函數(shù),created.

我們來(lái)看下title的效果:


小結(jié):

  • 我們上面采用的是比較普通的實(shí)現(xiàn)方式,我們會(huì)想到其實(shí)修改標(biāo)題的位置就是每一個(gè)路由對(duì)應(yīng)的.vue組件文件。
    -通過(guò)created生命周期函數(shù),執(zhí)行對(duì)應(yīng)的代碼進(jìn)行修改即可
  • 雖然效果可實(shí)現(xiàn)了,但一個(gè)個(gè)去修改顯然有點(diǎn)唐突+狼狽了(幾百個(gè)頁(yè)面的時(shí)候就顯然不合適這樣的操作去維護(hù))。

導(dǎo)航守衛(wèi)的使用

  • 真正的全局守衛(wèi)導(dǎo)航是在router/index.js里面配置的。
  • 我們首先拿到router對(duì)象,這個(gè)router對(duì)象里面有一個(gè)beforeEach()方法,這個(gè)beforeEach()方法里面有三個(gè)參數(shù),分別是to, from, next


  • 我們可以利用beforeEach來(lái)完成對(duì)導(dǎo)航標(biāo)題的修改。
  • 我們可以在鉤子當(dāng)中用meta來(lái)定義一些標(biāo)題。
  • 其次呢,利用導(dǎo)航守衛(wèi)修改我們的標(biāo)題。

beforeEach導(dǎo)航鉤子三個(gè)參數(shù)的解釋?zhuān)?/strong>

  • to: 即將進(jìn)入的目標(biāo)路由對(duì)象。
  • from: 當(dāng)前導(dǎo)航即將要離開(kāi)的路由對(duì)象。
  • next: 調(diào)用該方法后,才能進(jìn)入下一個(gè)鉤子,不調(diào)用一下next()方法的話,整個(gè)頁(yè)面的路由跳轉(zhuǎn)將會(huì)被攔截,next方法告訴瀏覽器下一步要干嘛,千萬(wàn)別給我攔截了。
  • 大概就是從from跳轉(zhuǎn)到to

顯然我們不能拿到to.title這樣一個(gè)的數(shù)據(jù)

  • 所以要在組件映射里面添加每個(gè)對(duì)應(yīng)的meta屬性(元數(shù)據(jù):描述數(shù)據(jù)的數(shù)據(jù))




    這樣全局導(dǎo)航守衛(wèi)效果總體就實(shí)現(xiàn)了,但還有一點(diǎn)瑕疵,就是當(dāng)我們點(diǎn)擊首頁(yè)的時(shí)候,title變成了undefine。



    為什么會(huì)這樣?
    這和我們?cè)谑醉?yè)里面使用了嵌套子路由有關(guān)系。
    我們嘗試打印to對(duì)象看下。

    所以我們只要找到matched(匹配)的0號(hào)位,就能解決子路由這塊的小bug




如果是后置鉤子函數(shù),即afterEach,不需要主動(dòng)調(diào)用next()函數(shù)。

  • 上面我們使用的導(dǎo)航守衛(wèi),叫做全局守衛(wèi)
  • 此外還有路由獨(dú)享的守衛(wèi)、組件內(nèi)的守衛(wèi)。

keep-alive遇上vue-router

keep-alive可以保留組件內(nèi)部切換回來(lái)的顯示之前用戶(hù)的瀏覽狀態(tài)。

比如我們當(dāng)前在首頁(yè),點(diǎn)擊了新聞詳情頁(yè)面子路由,然后去點(diǎn)擊了檔案,現(xiàn)在再回去點(diǎn)擊首頁(yè),發(fā)現(xiàn)它停留在了新聞頁(yè)面,而不是我們想回去剛剛瀏覽過(guò)的新聞詳情頁(yè)面,遇到這種狀況的話,就要使用keep-alive去解決了。



那為什么會(huì)出現(xiàn)這樣的情況呢?
我們用生命周期函數(shù)測(cè)試下就明白了。




我們可以看到,當(dāng)我們點(diǎn)擊首頁(yè)的時(shí)候,組件被創(chuàng)建生成,點(diǎn)擊其他頁(yè)面的時(shí)候,組件已經(jīng)銷(xiāo)毀了,如此一直循環(huán)下去,默認(rèn)顯示的都是新聞頁(yè)面,而不是新聞詳情頁(yè)面。

keep-alive(保持組件活著)概念理解,結(jié)合代碼解決上面提出的問(wèn)題。

  • keep-alive是Vue內(nèi)置的一個(gè)組件,可以使被包含的組件保留狀態(tài),或避免重新渲染。
    keep-alive有2個(gè)重要屬性
  • include - 字符串或正則表達(dá),只有匹配的組件會(huì)被緩存。
    -exclude - 字符串或正則表達(dá),任何匹配的組件都不會(huì)被緩存。


  • router-view也是一個(gè)組件,如果直接被包在keep-alive里面,所以路徑匹配到的試圖組件都會(huì)被緩存。



    我們還要注銷(xiāo)掉首頁(yè)下,默認(rèn)新聞頁(yè)面內(nèi)容展示。


我們需要用到組件內(nèi)的守衛(wèi)知識(shí):beforeRouteLeave
官網(wǎng):https://router.vuejs.org/zh/guide/advanced/navigation-guards.html


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容