Vue路由router詳解
模塊化的方式使用路由插件
(1)安裝
npm install vue-router
(2)構(gòu)建文件目錄
在src目錄下創(chuàng)建一個(gè)router文件夾,然后創(chuàng)建一個(gè)index.js
(3)這里我們通過模塊化的方式進(jìn)行創(chuàng)建路由,方便代碼的管理,這里只是對(duì)路插件進(jìn)行了注冊(cè),然后創(chuàng)建好路由對(duì)象。通過export default 關(guān)鍵字將創(chuàng)建好的路由對(duì)象暴露出去。
//index.js import VueRouter from 'vue-router' import Vue from 'vue' import Home from "../views/Home"; Vue.use(VueRouter)//注冊(cè)路由插件 export default new VueRouter({ routes:[{ path:'/', component:Home }] })
(4)在入口文件main.js引入創(chuàng)建好的路由對(duì)象,并且把他掛載到Vue實(shí)例中。
//main.js import Vue from 'vue' import App from './App.vue' import store from '@/store' import router from '@/router'//這里就是引入了我們創(chuàng)建好的路由對(duì)象。模塊化的編程思維 Vue.config.productionTip = false Vue.prototype.bus = new Vue() new Vue({ store, router, render: h => h(App), }).$mount('#app')
使用路由
聲明式導(dǎo)航
可以理解成,通過標(biāo)簽進(jìn)行跳轉(zhuǎn)
聲明式導(dǎo)航:<router-link :to="...">
或者 <router-link to="...">
定義路由規(guī)則
{ path:'/', component:Home name:home }
(1)router-link導(dǎo)航標(biāo)簽to屬性使用字符串方式
<router-link to="/">go to home</router-link>
(2)router-link導(dǎo)航標(biāo)簽to使用對(duì)象的方式
使用路徑進(jìn)行匹配
<router-link :to="{path:'/'}">go to home</router-link>
router-link導(dǎo)航標(biāo)簽to屬性使用對(duì)象的方式并且使用路由名稱進(jìn)行匹配
<router-link :to="{name:'home'}">go to home</router-link>
編程式導(dǎo)航
可以理解成JS進(jìn)行跳轉(zhuǎn)
編程式導(dǎo)航:router.push(...)
下面的例子包含了動(dòng)態(tài)路由匹配和query查詢參數(shù)的知識(shí),不清楚的可以先看了這兩者的內(nèi)容再回來(lái)看此處的內(nèi)容。
// 字符串 router.push('home') // 對(duì)象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: '123' }}) // 帶查詢參數(shù),變成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了 path,params 會(huì)被忽略,上述例子中的 query 并不屬于這種情況。取而代之的是下面例子的做法,你需要提供路由的 name 與params配合或手寫完整的帶有參數(shù)的 path:
const userId = '123' router.push({ name: 'user', params: { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 這里的 params 不生效 router.push({ path: '/user', params: { userId }}) // -> /user
動(dòng)態(tài)路由匹配
定義路由規(guī)則
{ path:'/user/:id', component:User name:user }
<router-link to="/user/01">go to home</router-link>
<router-link :to="{path:'/user/01'}">go to home</router-link>
<router-link :to="{name:'/user',params={id:'01'}}">go to home</router-link>
通過如上的方式進(jìn)行定義,可以通過$route.params.id 獲動(dòng)態(tài)路由參數(shù):id值為'01‘
注意:
當(dāng)使用對(duì)象的方式進(jìn)行匹配時(shí)候,不能通過path和params的方式。只能通過name和params的方式
如下方式,不能匹配到路由規(guī)則{path:'/user/:id'} ,如下表述只能被理解成'/user',
即使通過*通配符匹配到該路由,params也不會(huì)被傳遞過去,因?yàn)橐衟ath這個(gè)屬性就不會(huì)去解析params的屬性了。
{ // 會(huì)匹配所有路徑 path: '*' } { // 會(huì)匹配以 `/user-` 開頭的任意路徑 path: '/user-*' }
通配符匹配路徑
我們通常使用*捕獲其他意外的路徑,進(jìn)行個(gè)兜底的處理,通常將其導(dǎo)航到404錯(cuò)誤頁(yè)面。
<router-link to=“/user?name=zhangsan">...</router-link> <router-link :to="{path:'/user?zhangsan'}">...</router-link> <router-link :to="{path:'/user',query:{name:'zhangsan'}}">...</router-link> <router-link :to="{name:'user',query:{name:'zhangsan'}}">...</router-link>
當(dāng)使用一個(gè)通配符時(shí),$route.params 內(nèi)會(huì)自動(dòng)添加一個(gè)名為 pathMatch 參數(shù)。它包含了 URL 通過通配符被匹配的部分
查詢參數(shù)query
<router-link to=“/user?name=zhangsan">...</router-link> <router-link :to="{path:'/user?zhangsan'}">...</router-link> <router-link :to="{path:'/user',query:{name:'zhangsan'}}">...</router-link> <router-link :to="{name:'user',query:{name:'zhangsan'}}">...</router-link>
查詢參數(shù)不想動(dòng)態(tài)路由參數(shù)匹配那樣,就算使用了path,依然可以使用query進(jìn)行傳參;
以上query傳遞過來(lái)的參數(shù)可以通過this.$route.query.name
進(jìn)行獲取。
響應(yīng)路由參數(shù)的變化
如果路由從/user/01
導(dǎo)航到/user/02
,原來(lái)的組件實(shí)例會(huì)被復(fù)用。因?yàn)橛袃蓚€(gè)路由都渲染同一個(gè)組件,這意味著組件的生命周期鉤子不會(huì)被再次調(diào)用。因此需要通過其他方式進(jìn)行監(jiān)聽參數(shù)的變化來(lái)做出響應(yīng)。
(1)通過watch進(jìn)行監(jiān)聽
const User = { template: '...', watch: { $route(to, from) { // 對(duì)路由變化作出響應(yīng)... } } }
(2)通過導(dǎo)航守衛(wèi)進(jìn)行監(jiān)聽
const User = { template: '...', beforeRouteUpdate(to, from, next) { // react to route changes... // don't forget to call next() } }
命名路由,路由別名,重定向
特別地我把這三者的概念放在一起來(lái)闡述,是為了更好的去區(qū)分他們之間的區(qū)別。這些內(nèi)容都是在路由規(guī)則去配置的。
{ path: '/pageOne', component:PageOne, alias:"/firstPage", name:"pageOne", redirect:{name:'pageTwo'} }, { path: '/pageTwo', component:PageTwo, name:'pageTwo' }
(1)命名路由:可以理解成給這個(gè)路由取個(gè)名字
即使通過name屬性給路由取一個(gè)名字
routes: [ { path: '/user/:userId', name: 'user', component: User } ]
(2)路由別名:可以理解成這個(gè)路由的第二個(gè)名字。
例如:/a的別名是/b,當(dāng)用戶訪問/b的時(shí)候,URL會(huì)保持/b但是路由匹配到的內(nèi)容則為/a,也就是知識(shí)URL內(nèi)容顯示/b內(nèi)容實(shí)則是/a
注意了:這里別名要使用路徑的方式去表述,而不是跟命名路由那樣直接寫名字哦~
const router = new VueRouter({ routes: [ { path: '/a', component: A, alias: '/b' } ] })
(3)重定向:可以理解為訪問/a的時(shí)候直接跳轉(zhuǎn)到/b
重定向的表述有三種形式:
- 字符串
const router = new VueRouter({ routes: [ { path: '/a', redirect: '/b' } ] })
- 對(duì)象
const router = new VueRouter({ routes: [ { path: '/a', redirect: { name: 'foo' }} ] })
- 方法
const router = new VueRouter({ routes: [ { path: '/a', redirect: to => { // 方法接收 目標(biāo)路由 作為參數(shù) // return 重定向的 字符串路徑/路徑對(duì)象 }} ] })
嵌套路由
嵌套路由可以這么理解,所匹配的路由渲染出來(lái)的組件中包含路由組件,'/user'當(dāng)我們匹配到一個(gè)路由渲染出一個(gè)組件User,但是如果想繼續(xù)在User組件的<router-view ></router-view>繼續(xù)匹配。則我們要通過/user/childRouteName進(jìn)一步匹配。"childRouteName"就是我們路由規(guī)則children中對(duì)應(yīng)的path的值啦。
{ path: '/user', component: User, children: [ { // 當(dāng) /user//profile 匹配成功, // UserProfile 會(huì)被渲染在 User 的 <router-view> 中 path: 'profile', component: UserProfile }, { // 當(dāng) /user//posts 匹配成功 // UserPosts 會(huì)被渲染在 User 的 <router-view> 中 path: 'posts', component: UserPosts } ] }
APP.Vue中
<div id="app"> <router-view></router-view> </div>
User組件中
const User = { template: ` <div class="user"> <span>User組件</span> <router-view></router-view> </div> ` }
注意:
定義了嵌套路由,即定義了children的情況下,必須是完整的路由才可以匹配正確。也就是 當(dāng) /user/profile匹配成功,但是/user這樣是無(wú)法匹配成功的。
命名視圖
當(dāng)一個(gè)組件上同時(shí)渲染多個(gè)視圖,注意是同級(jí)展示多個(gè)視圖,而不是嵌套展示。那此時(shí)就可以通過命名視圖來(lái)解決這個(gè)問題。
路由規(guī)則定義
{ path:"/namingRoute", components:{//注意此處components是帶's'結(jié)尾的,之前單個(gè)的時(shí)候是不帶的。 default:Home, one:PageOne, two:PageTwo } }
組件定義
<router-view></router-view>//渲染default對(duì)應(yīng)的組件 <router-view name="one"></router-view>//渲染one對(duì)應(yīng)的組件 <router-view name="two"></router-view>//渲染two對(duì)應(yīng)的組件
當(dāng)URL為:/namingRoute的時(shí)候 匹配到該路由,則會(huì)按照對(duì)應(yīng)的router-view視圖組件進(jìn)行渲染。
導(dǎo)航守衛(wèi)
(1)全局守衛(wèi)
可以理解成通過全局router實(shí)例對(duì)象router進(jìn)行定義的守衛(wèi)。
- route.beforeEach(全局前置守衛(wèi))
使用方式:
beforeEach((to,from,next)=>{ //... })
- router.beforeResolve(全局解析守衛(wèi))
在所有組件內(nèi)守衛(wèi)和異步路由組件被解析之后,解析守衛(wèi)就被調(diào)用
使用方式:
router.beforeResolve((to, from, next) => { // ... })
- router.afterEach (全局后置鉤子)
鉤子不會(huì)接受 next 函數(shù)也不會(huì)改變導(dǎo)航本身:
使用方式:
router.afterEach((to, from) => { // ... })
使用的位置:通常在router文件夾下的index.js const router = new VueRouter({ ... }) //全局前置守衛(wèi) router.beforeEach((to, from, next) => { // ... }) //全局解析守衛(wèi) router.beforeResolve((to, from, next) => { // ... }) //全局后置鉤子 router.afterEach((to, from) => { // ... })
(2)路由獨(dú)享守衛(wèi)
可以理解成在路由規(guī)則上定義的守衛(wèi)
- beforeEnter
(3)組件內(nèi)守衛(wèi)
可以理解成在組件內(nèi)定義的守衛(wèi)
- beforeRouteEnter
還沒有創(chuàng)建組件實(shí)例,在該路由被confirm前調(diào)用。
const User = { template: `...`, beforeRouteEnter(to, from, next) { // 在渲染該組件的對(duì)應(yīng)路由被 confirm 前調(diào)用 // 不!能!獲取組件實(shí)例 `this` // 因?yàn)楫?dāng)守衛(wèi)執(zhí)行前,組件實(shí)例還沒被創(chuàng)建 } }
注意:
該守衛(wèi)不能直接使用this訪問vue實(shí)例對(duì)象,因?yàn)榇藭r(shí)組件實(shí)例還沒有被創(chuàng)建。但是可以通過給next方法傳遞回調(diào)來(lái)方位組件的實(shí)例。
給next()傳遞回調(diào),僅在beforeRouteEnter使用有效?。?!
beforeRouteEnter (to, from, next) { next(vm => { // 通過 `vm` 訪問組件實(shí)例 }) }
- beforeRouteUpdate (2.2 新增)
在路由改變且該組件被服用時(shí)調(diào)用
const User = { template: `...`, beforeRouteUpdate(to, from, next) { // 在當(dāng)前路由改變,但是該組件被復(fù)用時(shí)調(diào)用 // 舉例來(lái)說,對(duì)于一個(gè)帶有動(dòng)態(tài)參數(shù)的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉(zhuǎn)的時(shí)候, // 由于會(huì)渲染同樣的 Foo 組件,因此組件實(shí)例會(huì)被復(fù)用。而這個(gè)鉤子就會(huì)在這個(gè)情況下被調(diào)用。 // 可以訪問組件實(shí)例 `this` } }
- beforeRouteLeave
在導(dǎo)航離開該組件對(duì)應(yīng)的路由時(shí)調(diào)用
const User = { template: `...`, beforeRouteLeave(to, from, next) { // 導(dǎo)航離開該組件的對(duì)應(yīng)路由時(shí)調(diào)用 // 可以訪問組件實(shí)例 `this` } }
導(dǎo)航解析的流程
正常首次訪問路由的執(zhí)行順序
- beforeEach 全局的路由前置守衛(wèi)
- beforeEnter 獨(dú)享路由守衛(wèi)
- beforeRouteEnter 組件路由守衛(wèi)
- beforeResolve 全局路由解析守衛(wèi)
- afterEach 全局路由后置鉤子
- Dom渲染
- 調(diào)用beforeRouteEnter 組件路由守衛(wèi)中傳遞給next的回調(diào)函數(shù)。并且把創(chuàng)建號(hào)的組件實(shí)例作為回調(diào)函數(shù)的參數(shù)傳入。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
詳解使用jest對(duì)vue項(xiàng)目進(jìn)行單元測(cè)試
這篇文章主要介紹了詳解使用jest對(duì)vue項(xiàng)目進(jìn)行單元測(cè)試,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2018-09-09vue axios 給生產(chǎn)環(huán)境和發(fā)布環(huán)境配置不同的接口地址(推薦)
這篇文章主要介紹了vue axios 給生產(chǎn)環(huán)境和發(fā)布環(huán)境配置不同的接口地址,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-05-05Vue3.x的版本中build后dist文件中出現(xiàn)legacy的js文件問題
這篇文章主要介紹了Vue3.x的版本中build后dist文件中出現(xiàn)legacy的js文件問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07vue2導(dǎo)入使用vue-codemirror組件的教程詳解
vue-codemirror是一個(gè)基于Vue的代碼在線編輯器組件,它封裝了CodeMirror編輯器,使得在Vue項(xiàng)目中可以方便地使用CodeMirror,下面我們就來(lái)看看vue-codemirror的具體使用吧2024-02-02基于element日歷組件實(shí)現(xiàn)簽卡記錄
這篇文章主要為大家詳細(xì)介紹了基于element日歷組件實(shí)現(xiàn)簽卡記錄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08vue2如何使用vue-i18n搭建多語(yǔ)言切換環(huán)境
這篇文章主要介紹了vue2-使用vue-i18n搭建多語(yǔ)言切換環(huán)境的相關(guān)知識(shí),在data(){}中獲取的變量存在更新this.$i18n.locale的值時(shí)無(wú)法自動(dòng)切換的問題,需要刷新頁(yè)面才能切換語(yǔ)言,感興趣的朋友一起看看吧2023-12-12