一、vue路由
vue路由:vue-router
??vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,適合用于構建單頁面應用。vue的單頁面應用是基于路由和組件的,路由用于設定訪問路徑,并將路徑和組件映射起來。傳統(tǒng)的頁面應用,是用一些超鏈接來實現(xiàn)頁面切換和跳轉的。在vue-router單頁面應用中,則是路徑之間的切換,也就是組件的切換。
https://router.vuejs.org/zh/installation.html
安裝:
D:\vue-project>npm install vue-router
單頁面應用有兩個路徑:/home和/about,與這兩個路徑對應的是兩個組件Home和About。

二、創(chuàng)建路由
- 引入路由
//導入路由
import Router from 'vue-router'
//使用/注冊
Vue.use(Router)
- 創(chuàng)建路由對象
//創(chuàng)建路由對象
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
]
})
- 創(chuàng)建組件,并配置路由
創(chuàng)建Home組件:
//Home.vue
<template>
<div class="container">
<h2>Home</h2>
</div>
</template>
<script>
export default {
name: 'Home'
}
</script>
<style scoped>
</style>
// router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
Vue.use(Router)
//創(chuàng)建路由對象
export default new Router({
routes: [
{
path: '/Home',
name: 'Home',
component: Home
}
]
})
注: @指向src目錄
- 路由切換 router-link
<!-- <router-link> 默認會被渲染成一個 `<a>` 標簽 -->
<router-link to="/Home">Home</router-link>
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
- router-view
主要是構建 SPA (單頁應用) 時,方便渲染你指定路由對應的組件??梢?router-view 當做是一個容器,它渲染的組件是你使用 vue-router 指定的。
//app.vue
<template>
<div id="app">
<!--渲染路由顯示-->
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
- 動態(tài)路由匹配
我們經(jīng)常需要把某種模式匹配到的所有路由,全都映射到同個組件。例如,我們有一個 User 組件,對于所有 ID 各不相同的用戶,都要使用這個組件來渲染。那么,我們可以在 vue-router 的路由路徑中使用“動態(tài)路徑參數(shù)”(dynamic segment) 來達到這個效果:
routes: [
// 動態(tài)路徑參數(shù) 以冒號開頭
{ path: '/user/:id', component: User }
]
一個“路徑參數(shù)”使用冒號 : 標記。當匹配到一個路由時,參數(shù)值會被設置到 this.$route.params,可以在每個組件內(nèi)使用。于是,我們可以更新 User 的模板,輸出當前用戶的 ID:
# $route一定不要加this。
{{ $route.params.id }}
<template>
<div id="container">
<div v-if="'menu'===$route.params.id">
菜單管理
</div>
<div v-if="'user'===$route.params.id">
用戶管理
</div>
</div>
</template>
<script>
export default {};
</script>
<style scoped>
</style>


可以在一個路由中設置多段“路徑參數(shù)”,對應的值都會設置到 $route.params 中。例如:
| 模式 | 匹配路徑 | $route.params |
|---|---|---|
| /user/:username | /user/evan | { username: 'evan' } |
| /user/:username/post/:post_id | /user/evan/post/123 | { username: 'evan', post_id: '123' } |
除了$route.params 外,$route 對象還提供了其它有用的信息,例如,$route.query (如果 URL 中有查詢參數(shù))、$route.hash 等等。
三、嵌套路由
實際應用界面,通常由多層嵌套的組件組合而成。
比如,我們 “首頁”組件中,還嵌套著 “登錄”和 “注冊”組件,那么URL對應就是/home/login和/home/reg。
<template id="home">
<!-- 注意:組件只能有一個根元素,所以我們包裝到這個div中 -->
<div>
<h2>首頁</h2>
<router-link to="/home/login">登錄</router-link>
<router-link to="/home/reg">注冊</router-link>
<!-- 路由匹配到的組件將渲染在這里 -->
<router-view></router-view>
</div>
</template>
模板
新聞
<template id="news">
<div>新聞</div>
</template>
登錄
<template id="login">
<div>登錄界面</div>
</template>
注冊
<template id="reg">
<div>注冊界面</div>
</template>
定義路由
// 2. 定義路由
const routes = [
//重定向
{ path: '/', redirect: '/home' },
{
path: '/home',
component: Home,
children:[
{ path: 'login', component: Login},
{ path: 'reg', component: Reg}
]
},
{ path: '/news', component: News}
]
四、重定向
{ path: '/', redirect: '/home' },
五、路由高亮
在index.js 中, 添加 路由選中class名
默認是 router-link-active, 更改
active-class是vue-router模塊的router-link組件中的屬性,用來做選中樣式的切換;
https://router.vuejs.org/zh/api/#active-class
- 組件:Home.vue
<template>
<div class="container">
<ul>
<li><router-link to="/" exact>首頁</router-link></li>
<li><router-link to="/List">列表</router-link></li>
<li><router-link to="/About">關于我們</router-link></li>
</ul>
<br>
<router-view/>
</div>
</template>
- 路由:index.js
Vue.use(Router)
//創(chuàng)建路由對象
export default new Router({
mode: 'history', // 去掉路由地址的#
linkActiveClass: "active",
// linkExactActiveClass:"active",
routes: [
{
path: '/',
name: 'Home',
component: Home,
children:[
{
path: '/List',
name: 'List',
component: List
},
{
path: '/About',
name: 'About',
component: About
}
]
}]
})
- 在全局中配置, css 樣式:
.active {
color: red
}
對于匹配 / 的, 會始終顯示高亮, 需要添加 exact 屬性;
<li><router-link :to="index" exact>首頁</router-link></li>

六、參數(shù)傳遞
(一) 在 router-link 中, 使用 :to={} 的形式進行傳遞參數(shù)
#使用對象傳參
<li><router-link :to="{ name: 'Master', params:{count: 100, obj: user}}">用戶列表</router-link></li>
<script>
export default {
data() {
return { user: {name:"張三",age:20} };
}
};
</script>
在 master 頁面, 接受參數(shù)
<template>
<div>
用戶: {{ $route.params.count }} - {{ $route.params.obj.name }}
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
(二)this.$route.query和this.$route.params的使用與區(qū)別
1. this.$route.query
1)路由 index.js
Vue.use(Router)
//創(chuàng)建路由對象
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home,
children: [
{
path: '/List',
name: 'List',
component: List
},
{
path: '/About',
name: 'About',
component: About
}
]
}, {
path: '/ListTest',
name: 'ListTest',
component: List
}
]}
)
2) 聲明式導航傳參
<template>
<div class="container">
<div class="top">
<ul>
<!-- 標簽式傳參 -->
<li>
<router-link :to="{name:'List',params: { name: '張三',age: 20},query: { queryId: 1 }}">列表</router-link>
</li>
</ul>
</div>
<div class="buttom">
<router-view/>
</div>
</div>
</template>
<style scoped>
.buttom{
clear: both;
}
ul {
list-style: none;
}
li {
float: left;
margin: 20px;
}
</style>
3) 編程式導航:
<template>
<div class="container">
<!--編程式導航-->
<button @click="urlLink">關于我們</button>
</div>
</template>
<script>
export default {
name: "Home",
data() {
return { item: { id: 1, name: "西瓜" } };
},
methods: {
urlLink() {
//編程跳轉寫在一個函數(shù)里面,通過click等方法來觸發(fā)
this.$router.push("/ListTest");
}
}
};
</script>
4) 編程式導航傳參:
<template>
<div class="container">
<!--編程式導航-->
<button @click="urlLink">關于我們</button>
</div>
</template>
<script>
export default {
name: "Home",
data() {
return { item: { id: 1, name: "西瓜" } };
},
methods: {
urlLink() {
this.$router.push({ name:'ListTest',params: { name: '張三',age: 20},query: { queryId: 1}});
}
}
};
</script>
3) 獲取參數(shù)
組件:List.vue
<template>
<div class="container">
列表
<!-- 注意:$route 就route不要寫錯 -->
{{ $route.params.name }}<br>
{{$route.query.queryId}}
</div>
</template>
4) url的表現(xiàn)形式(url中帶有參數(shù))
http://localhost:8080/ListTest?queryId=1
2. params傳參和query傳參有什么區(qū)別?
1、用法上的
剛query要用path來引入,params要用name來引入,接收參數(shù)都是類似的,分別是this.route.params.name。
注意接收參數(shù)的時候,已經(jīng)是router。
2、展示上的
query更加類似于我們ajax中get傳參,params則類似于post,說的再簡單一點,前者在瀏覽器地址欄中顯示參數(shù),后者則不顯示。
3、params是路由的一部分,必須要有。query是拼接在url后面的參數(shù),沒有也沒關系。
params一旦設置在路由,params就是路由的一部分,如果這個路由有params傳參,但是在跳轉的時候沒有傳這個參數(shù),會導致跳轉失敗或者頁面會沒有內(nèi)容。
比如:跳轉/router1/:id
<router-link :to="{ name:'router1',params: { id: status}}" >正確</router-link>
<router-link :to="{ name:'router1',params: { id2: status}}">錯誤</router-link>
七、多視圖(命名視圖)
https://router.vuejs.org/zh/guide/essentials/named-views.html
有時候想同時 (同級) 展示多個視圖,而不是嵌套展示,例如創(chuàng)建一個布局,有 sidebar (側導航) 和 main (主內(nèi)容) 兩個視圖,這個時候命名視圖就派上用場了。你可以在界面中擁有多個單獨命名的視圖,而不是只有一個單獨的出口。如果 router-view 沒有設置名字,那么默認為 default。
- app.vue
<template>
<div id="app">
<router-view class="top" name="top"/>
<router-view class="left" name="left"/>
<router-view class="main"/>
</div>
</template>
<script>
export default {
name: "App"
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
margin: auto;
}
.active {
color: red;
}
.top {
height: 160px;
background-color: blueviolet;
}
.left {
float: left;
width: 200px;
background-color: chartreuse;
height: 500px;
}
.main {
float: left;
background-color:darkcyan;
width: 1200px;
height: 500px;
}
</style>
- 路由index.js
// 使用組件
Vue.use(Router)
// 導出一個默認的組件
export default new Router({
routes: [
{
path: '/layout',
components: {
default: Main,
top: Top,
left: Left
}
}]
})
- 分別創(chuàng)建3個組件
left.vue
<template>
<div id="container">
菜單視圖
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
main.vue
<template>
<div id="container">
內(nèi)容視圖
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
top.vue
<template>
<div id="container">
頂部導航視圖
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
this.$router.push()
跳轉到不同的url,但這個方法會向history棧添加一個記錄,點擊后退會返回到上一個頁面。
this.router.replace
跳轉到指定url路徑,但是history棧中不會有記錄,點擊返回會跳轉到上上個頁面
八、路由常用屬性
1.$route.path
字符串,等于當前路由對象的路徑,會被解析為絕對路徑,如 "/home/news" 。
2.$route.params
對象,包含路由中的動態(tài)片段和全匹配片段的鍵值對。
3.$route.query
對象,包含路由中查詢參數(shù)的鍵值對。例如,對于 /home/news/detail/01?favorite=yes ,會得到$route.query.favorite == ‘yes‘ 。
4.$route.router
路由規(guī)則所屬的路由器(以及其所屬的組件)。
5.$route.matched
數(shù)組,包含當前匹配的路徑中所包含的所有片段所對應的配置參數(shù)對象。
6.$route.name
當前路徑的名字,如果沒有使用具名路徑,則名字為空。
九、Vue:router的beforeEach與afterEach鉤子函數(shù)
??在路由跳轉的時候,我們需要一些權限判斷或者其他操作。這個時候就需要使用路由的鉤子函數(shù)。
定義:路由鉤子主要是給使用者在路由發(fā)生變化時進行一些特殊的處理而定義的函數(shù)。
總體來講vue里面提供了三大類鉤子,兩種函數(shù)
1、全局鉤子
2、某個路由的鉤子
3、組件內(nèi)鉤子
兩種函數(shù):
1、在跳轉之前執(zhí)行
/*在跳轉之前執(zhí)行*/
Vue.beforeEach(function(to,form,next){})
- 在跳轉之后判斷
/*在跳轉之后判斷*/
Vue.afterEach(function(to,form))
全局鉤子函數(shù):
router.beforeEach((to, from, next) => {
let token = router.app.$storage.fetch("token");
let needAuth = to.matched.some(item => item.meta.login);
if(!token && needAuth) return next({path: "/login"});
next();
});
beforeEach函數(shù)有三個參數(shù):
to:router即將進入的路由對象
from:當前導航即將離開的路由
next:Function,進行管道中的一個鉤子,如果執(zhí)行完了,則導航的狀態(tài)就是 confirmed (確認的);否則為false,終止導航。
afterEach函數(shù)不用傳next()函數(shù)
某個路由的鉤子函數(shù)
顧名思義,它是寫在某個路由里頭的函數(shù),本質上跟組件內(nèi)函數(shù)沒有區(qū)別。
const router = new VueRouter({
routes: [
{
path: '/login',
component: Login,
beforeEnter: (to, from, next) => {
// ...
},
beforeLeave: (to, from, next) => {
// ...
}
}
]
})
路由組件的鉤子
注意:這里說的是路由組件!
路由組件屬于組件,但組件不等同于路由組件!所謂的路由組件:直接定義在router中component處的組件。如
var routes = [
{
path:'/home',
component:home,
name:"home"
}
]
在子組件中調用路由的鉤子函數(shù)時無效的。
示例:
permission.js
/**
* 全站權限配置
*/
import router from '@/router.js'
// 最先執(zhí)行的是 beforeEach鉤子,所有路由開始的時候最先執(zhí)行
router.beforeEach((to, from, next) => {
console.log("跳轉路徑:"+to);
console.log("當前路徑:"+from);
// 繼續(xù)執(zhí)行
next();
});
// 在跳轉之后判斷
router.afterEach(() => {
console.log("路由執(zhí)行完畢");
});
main.js
// 導入權限文件
import "@/utils/permission.js";
十、router-view組件間傳值
- router-view 子組件傳父組件
父組件:
<template>
<div id="app">
一個簡單的測試
<router-view @getUser="getUserInfo"/>
</div>
</template>
<script>
export default {
methods:{
getUserInfo(val){
console.log(val+"-》父組件");
}
}
}
</script>
子組件:
<template>
<div class="home">
<input type="button" @click="test" value="登錄">
</div>
</template>
<script>
export default {
name: "home",
components: {
},
methods: {
test() {
this.$emit("getUser", "我是home組件");
}
}
};
</script>
測試:

- 父傳子
父組件:
<template>
<div id="app">
一個簡單的測試
<router-view :userSubValue="userData" />
</div>
</template>
<script>
export default {
data(){
return { userData:" 父組件數(shù)據(jù)"}
}
};
</script>
子組件:
<template>
<div class="home">{{user}}</div>
</template>
<script>
export default {
name: "home",
data() {
return { user: "" };
},
props: ["userSubValue"],
created() {
this.getUserValue();
},
methods: {
getUserValue() {
this.user=this.userSubValue;
}
}
};
</script>
路由:router.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/home',
name: 'home',
component: () => import(/* webpackChunkName: "about" */ './views/Home.vue')
},
{
path: '/about',
name: 'about',
component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
}
]
})
測試:

- 示例
使用router-view將子組件home.vue數(shù)據(jù)傳給app.vue,app.vue再將數(shù)據(jù)傳給一個子組件about.vue。
home.vue
<template>
<div class="home">
<input type="button" @click="test" value="登錄">
</div>
</template>
<script>
export default {
name: "home",
components: {
},
methods: {
test() {
this.$emit("getUser", "我是home組件");
}
}
};
</script>
app.vue
<template>
<div id="app">
<about :userInfo="user"/>
一個簡單的測試
<router-view @getUser="getUserInfo" />
</div>
</template>
<script>
import About from "@/views/About.vue";
export default {
data(){
return { user:""}
},
components: {
About
},
methods: {
getUserInfo(val) {
this.user=val;
console.log(val + "-》父組件");
}
}
};
</script>
about.vue
<template>
<div class="about">
<h1>這是about組件</h1>
{{userInfo}}
</div>
</template>
<script>
export default {
props: { userInfo: String },
data() {
return { msg: "" };
}
};
</script>
路由:router.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/home',
name: 'home',
component: () => import(/* webpackChunkName: "about" */ './views/Home.vue')
},
{
path: '/about',
name: 'about',
component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
}
]
})
測試:


十一、常見問題
- NavigationDuplicated {_name: "NavigationDuplicated", name: "NavigationDuplicated", message: "Navigating to current location ("/welcome/index") is not allowed"
原因:在路由中添加了相同的路由。
解決:
重寫路由的push方法:
/**
* 重寫路由的push方法
*/
const routerPush = Router.prototype.push
Router.prototype.push = function push(location) {
return routerPush.call(this, location).catch(error=> error)
}