一. 安裝和引入
直接下載 / CDN
https://unpkg.com/vue-router/dist/vue-router.js
Unpkg.com 提供了基于 NPM 的 CDN 鏈接。上面的鏈接會(huì)一直指向在 NPM 發(fā)布的最新版本。你也可以像https://unpkg.com/vue-router@2.0.0/dist/vue-router.js
這樣指定 版本號(hào) 或者 Tag。
在 Vue 后面加載 vue-router
,它會(huì)自動(dòng)安裝的:
// html
<script src="/path/to/vue.js"></script>
<script src="/path/to/vue-router.js"></script>
NPM
npm install vue-router --save
如果在一個(gè)模塊化工程中使用它,必須要通過(guò) Vue.use() 明確地安裝路由功能:
// main.js
import Vue from 'vue'
import router from 'vue-router'
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
});
如果使用全局的 script 標(biāo)簽,則無(wú)須如此(手動(dòng)安裝)。
構(gòu)建開(kāi)發(fā)版
如果你想使用最新的開(kāi)發(fā)版,就得從 GitHub 上直接 clone,然后自己 build 一個(gè) vue-router。
git clone https://github.com/vuejs/vue-router.git node_modules/vue-router
cd node_modules/vue-router
npm install
npm run build
引入
router.js 的配置
在src文件夾下創(chuàng)建router文件并新建一個(gè)router.js文件
首先引入 vue-router組件,Vue.use是用來(lái)加載全局組件的。那下面我們就開(kāi)始看看這個(gè)VueRouter的寫法和配置吧。
mode:
默認(rèn)為hash,但是用hash模式的話,頁(yè)面地址會(huì)變成被加個(gè)#號(hào)比較難看了http://localhost:8080/#/linkParams/xuxiao
所以一般我們會(huì)采用 history模式,它會(huì)使得我們的地址像平常一樣。http://localhost:8080/linkParams/xuxiao
base
應(yīng)用的基路徑。例如,如果整個(gè)單頁(yè)應(yīng)用服務(wù)在 /app/ 下,然后 base 就應(yīng)該設(shè)為 "/app/"。
一般寫成 __dirname,在webpack中有配置。
routes
routes:就是我們的大核心了,里面包含我們所有的頁(yè)面配置。
path:很簡(jiǎn)單,就是我們的訪問(wèn)這個(gè)頁(yè)面的路徑
name:給這個(gè)頁(yè)面路徑定義一個(gè)名字,當(dāng)在頁(yè)面進(jìn)行跳轉(zhuǎn)的時(shí)候也可以用名字跳轉(zhuǎn),要唯一喲
component:組件,就是咱們?cè)谧钌厦嬉氲?import ...了,當(dāng)然這個(gè)組件的寫法還有一種懶加載
懶加載的方式,我們就不需要再用import去引入組件了,直接如下即可。懶加載的好處是當(dāng)你訪問(wèn)到這個(gè)頁(yè)面的時(shí)候才會(huì)去加載相關(guān)資源,這樣的話能提高頁(yè)面的訪問(wèn)速度。
component: resolve => require(['./page/linkParamsQuestion.vue'], resolve)
// router下的index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router);
export default new Router({
mode:"history",
routes: [
{
path: '/more/fag',
name: 'fag',
component: fag
},
{
path: '/',
name: 'followers',
component: follower
},
{
path: '/followers',
name: 'followers',
component: follower
},
{
path: '/likes',
name: 'like',
component: like
},
{
path: '/more',
name: 'more',
component: more,
children:[
// {
// path: '/more/fag',
// name: 'fag',
// component: fag,
// }
]
}
]
})
二. router的使用
1. router傳參
路由匹配參數(shù)
首先在路由配置文件router.js中做好配置。標(biāo)紅出就是對(duì) /linkParams/的路徑做攔截,這種類型的鏈接后面的內(nèi)容會(huì)被vue-router映射成name參數(shù)。
代碼中獲取name的方式:
let name = this.$route.params.name; // 鏈接里的name被封裝進(jìn)了 this.$route.params
Get請(qǐng)求傳參
如同:你完全可以在鏈接后加上?進(jìn)行傳參。
示例:http://localhost:8080/linkParamsQuestion?age=18
項(xiàng)目里獲取:
let age = this.$route.query.age; //問(wèn)號(hào)后面參數(shù)會(huì)被封裝進(jìn) this.$route.query;
編程式導(dǎo)航
這里就開(kāi)始利用vue-router講發(fā)起跳轉(zhuǎn)了。其實(shí)也非常簡(jiǎn)單,主要利用 <router-link>來(lái)創(chuàng)建可跳轉(zhuǎn)鏈接,還可以在方法里利用 this.$router.push('xxx') 來(lái)進(jìn)行跳轉(zhuǎn)。
樣例: <router-link to="/linkParams/xuxiao">點(diǎn)我不會(huì)懷孕</router-link>
上面的這個(gè)router-link就相當(dāng)于加了個(gè)可跳轉(zhuǎn)屬性。
至于this.$router.push這里直接用官網(wǎng)的荔枝了
// 字符串,這里的字符串是路徑path匹配噢,不是router配置里的name
this.$router.push('home')
// 對(duì)象
this.$router.push({ path: 'home' })
// 命名的路由 這里會(huì)變成 /user/123
this.$router.push({ name: 'user', params: { userId: 123 }})
// 帶查詢參數(shù),變成 /register?plan=private
this.$router.push({ path: 'register', query: { plan: 'private' }})
導(dǎo)航鉤子
導(dǎo)航鉤子函數(shù),主要是在導(dǎo)航跳轉(zhuǎn)的時(shí)候做一些操作,比如可以做登錄的攔截,而鉤子函數(shù)根據(jù)其生效的范圍可以分為 全局鉤子函數(shù)、路由獨(dú)享鉤子函數(shù)和組件內(nèi)鉤子函數(shù)。
全局鉤子函數(shù)
可以直接在路由配置文件router.js里編寫代碼邏輯。可以做一些全局性的路由攔截。
router.beforeEach((to, from, next)=>{
//do something
next();
});
router.afterEach((to, from, next) => {
console.log(to.path);
});
每個(gè)鉤子方法接收三個(gè)參數(shù):
to: Route: 即將要進(jìn)入的目標(biāo) 路由對(duì)象
from: Route: 當(dāng)前導(dǎo)航正要離開(kāi)的路由
next: Function: 一定要調(diào)用該方法來(lái) resolve 這個(gè)鉤子。執(zhí)行效果依賴 next 方法的調(diào)用參數(shù)。
next(): 進(jìn)行管道中的下一個(gè)鉤子。如果全部鉤子執(zhí)行完了,則導(dǎo)航的狀態(tài)就是 confirmed (確認(rèn)的)。
next(false): 中斷當(dāng)前的導(dǎo)航。如果瀏覽器的 URL 改變了(可能是用戶手動(dòng)或者瀏覽器后退按鈕),那么 URL 地址會(huì)重置到 from 路由對(duì)應(yīng)的地址。
next('/') 或者 next({ path: '/' }): 跳轉(zhuǎn)到一個(gè)不同的地址。當(dāng)前的導(dǎo)航被中斷,然后進(jìn)行一個(gè)新的導(dǎo)航。
確保要調(diào)用 next 方法,否則鉤子就不會(huì)被 resolved。
路由獨(dú)享鉤子函數(shù)
可以做一些單個(gè)路由的跳轉(zhuǎn)攔截。在配置文件編寫代碼即可
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
組件內(nèi)鉤子函數(shù)
更細(xì)粒度的路由攔截,只針對(duì)一個(gè)進(jìn)入某一個(gè)組件的攔截。
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染該組件的對(duì)應(yīng)路由被 confirm 前調(diào)用
// 不!能!獲取組件實(shí)例 `this`
// 因?yàn)楫?dāng)鉤子執(zhí)行前,組件實(shí)例還沒(méi)被創(chuàng)建
},
beforeRouteUpdate (to, from, next) {
// 在當(dāng)前路由改變,但是該組件被復(fù)用時(shí)調(diào)用
// 舉例來(lái)說(shuō),對(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)用。
// 可以訪問(wèn)組件實(shí)例 `this`
},
beforeRouteLeave (to, from, next) {
// 導(dǎo)航離開(kāi)該組件的對(duì)應(yīng)路由時(shí)調(diào)用
// 可以訪問(wèn)組件實(shí)例 `this`
}
}
其他知識(shí)點(diǎn)
滾動(dòng)行為
在利用vue-router去做跳轉(zhuǎn)的時(shí)候,到了新頁(yè)面如果對(duì)頁(yè)面的滾動(dòng)條位置有要求的話,可以利用下面這個(gè)方法。
const router = new VueRouter({
routes: [...],
scrollBehavior (to, from, savedPosition) {
// return 期望滾動(dòng)到哪個(gè)的位置
}
})
scrollBehavior 方法接收 to 和 from 路由對(duì)象。
第三個(gè)參數(shù) savedPosition 當(dāng)且僅當(dāng) popstate 導(dǎo)航 (mode為 history 通過(guò)瀏覽器的 前進(jìn)/后退 按鈕觸發(fā)) 時(shí)才可用。
這里就不細(xì)致的講了,文檔都有也非常簡(jiǎn)單,記住有這個(gè)東西就行。
//所有路由新頁(yè)面滾動(dòng)到頂部:
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
//如果有錨點(diǎn)
scrollBehavior (to, from, savedPosition) {
if (to.hash) {
return {
selector: to.hash
}
}
}
路由元信息
這個(gè)概念非常簡(jiǎn)單,就是在路由配置里有個(gè)屬性叫 meta,它的數(shù)據(jù)結(jié)構(gòu)是一個(gè)對(duì)象。你可以放一些key-value進(jìn)去,方便在鉤子函數(shù)執(zhí)行的時(shí)候用。
舉個(gè)例子,你要配置哪幾個(gè)頁(yè)面需要登錄的時(shí)候,你可以在meta中加入一個(gè) requiresAuth標(biāo)志位。
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
meta: { requiresAuth: true }
}
]
})
然后在 全局鉤子函數(shù) beforeEach中去校驗(yàn)?zāi)繕?biāo)頁(yè)面是否需要登錄。
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
//校驗(yàn)這個(gè)目標(biāo)頁(yè)面是否需要登錄
if (!auth.loggedIn()) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // 確保一定要調(diào)用 next()
}
})
這個(gè)auth.loggedIn 方法是外部引入的,你可以先寫好一個(gè)校驗(yàn)是否登錄的方法,再import進(jìn) router.js中去判斷。
項(xiàng)目中出現(xiàn)的問(wèn)題
1. 切換路由后改變組件數(shù)據(jù)
//組件
<template>
<div>{{header_msg}}</div>
</template>
export default {
data(){
return {
header_msg:'Get Followers',
}
},
watch: {
//不同path下 header_msg顯示的信息不同
'$route' (to, from) {
if(to.name === 'like'){
this.header_msg = 'Get Likes';
this.faq = false
}else if(to.name === 'more'){
this.header_msg = 'More';
this.faq = false
}else if(to.name === 'followers'){
this.header_msg = 'Get Followers';
this.faq = false
}else if(to.name === 'fag'){
this.faq = true
}
}
}
}
2.解決vue-router嵌套路由(子路由)在history模式下刷新無(wú)法渲染頁(yè)面的問(wèn)題
異常描述:
本來(lái)使用的是vue-router的hash模式,但是hash模式下url需要帶“#”符號(hào),不僅看起來(lái)不舒服,而且有些場(chǎng)景下是會(huì)破壞路由中的"#"(微信分享頁(yè)面就會(huì)把"#"后邊的內(nèi)容處理掉),所以就需要使用history模式,然后就讓后端改下nginx配置:
location / { try_files $uri $uri/ /index.html; }
vue-router使用history模式+使用嵌套路由:
const router = new Router({
mode: 'history',
routes: [
{
path: '/',
component: mall,
name: 'mall'
},
……
//我的銀行卡
{
path: '/myCard',
meta: { requireAuth: true },
component: myCard,
name: 'myCard',
children:[
{ path:'', component: card},
{ path:'add', component: add}
]
}
……
]
})
訪問(wèn)路由和嵌套路由頁(yè)面,顯示正常,但是刷新頁(yè)面的時(shí)候,嵌套路由頁(yè)面css樣式失效了:
解決問(wèn)題:
先考慮的主Vue中以Import的方式引入靜態(tài)樣式文件,的確可行,但是最后發(fā)現(xiàn),直接修改index.html文件中的靜態(tài)文件引入路徑就OK了:
修改前:
<link rel="stylesheet" href="./static/css/layout.css">
修改后
<link rel="stylesheet" href="/static/css/layout.css">
原理:
./ 是指用戶所在的當(dāng)前目錄(相對(duì)路徑);
/ 是指根目錄(絕對(duì)路徑,項(xiàng)目根目錄),也就是項(xiàng)目根目錄;
對(duì)于hash模式,根路徑是固定的,就是項(xiàng)目的根目錄,但是history模式下,以 / 開(kāi)頭的嵌套路徑會(huì)被當(dāng)作根路徑,所以使用“./”引入文件,就會(huì)找不到文件了,因?yàn)槲募旧砭褪窃陧?xiàng)目根目錄下的,并不在嵌套路徑這個(gè)目錄下。
總結(jié),無(wú)論hash模式還是history模式,可以直接使用“/”從項(xiàng)目根目錄引入靜態(tài)文件。
3. Vue默認(rèn)首頁(yè)router激活一直存在
異常描述:
在給router-link-active添加完樣式后在發(fā)現(xiàn)默認(rèn)路由('/')樣式一直存在。
解決:給router-link添加exact屬性
<router-link class="my-bar-item" to="/" exact>首頁(yè)</router-link>