本文目錄:
- 1.什么是前端路由
- 2.vue-router使用步驟
- 3.什么是單頁應用
- 4.配置路由
- 5.使用router-link實現跳轉
- 6.嵌套路由
- 7.命名路由
- 8.命名視圖
- 9.重定向
- 10.別名
- 11.編程式導航
- 12.動態(tài)路由匹配
- 13.路由組件傳參
- 14.記錄滾動位置
- 15.vue-router中的全局鉤子函數
- 16.vue-router中寫到路由記錄里的鉤子函數
- 17.寫在組件內部的路由鉤子函數
- 18.路由切換的動畫效果
1.什么是前端路由
路由這個概念最先是后端出現的,發(fā)送不同的請求,后端根據請求的不同返回不同的資源,這個時候的url是和后端交互的,需要在后端去配置路由的跳轉,這種開發(fā)方式有兩個特點,一是整個項目中前端代碼和后端代碼是柔在一起的,通常都是需要模版引擎來支持,代碼雜糅在一起后不方便本地開發(fā)調試,一旦后端代碼有錯誤,前端無法進行開發(fā),前端被限制在后端的開發(fā)方式中,效率很低,項目通常是后端主導,二是每次切換一個頁面都需要去重新請求服務器,即使兩個頁面有很多相似的地方都需要去重新請求,隨著單頁應用的發(fā)揚光大,MVVM概念興起,前后端分離以及前端工程化的發(fā)展,前端所做的事情越來越多,前端圈快速崛起。這里說的單頁應用,通俗的說就是一個頁面,是無刷新的,url變化,對應的是組件的切換,前端路由是為了實現這種單頁應用而出現的??偨Y起來就是前端路由就是在前端去控制不同url路徑,切換不同的組件,可以認為url和組件是一種映射關系
2.vue-router使用步驟
1.安裝模塊
npm install vue-router --save
2.引入模塊(在router文件夾中的index.js中引入,先import Vue from 'vue',然后)
import VueRouter from 'vue-router'
3.作為Vue的插件
Vue.use(VueRouter)
4.創(chuàng)建路由實例對象
const router = new VueRouter({
routes: [
{
path: '/',
component: Home
},
{
path: '/questions',
component: Questions
},
{
path: '/vip',
component: Vip
},
{
path: '/course',
component: Course
}
]
})
//對router進行導出
export default router
5.注入Vue選項參數(在main.js中進行引入)
import router from './router'
new Vue({
router
})
6.告訴路由渲染的位置
匹配上的組件會被渲染到router-view這個位置
<router-view></router-view>
7.放置跳轉標簽
路由最開始默認就有一個#號
<a href = '#/'></a>
<a href = '#/question'></a>
<a href = '#/vip'></a>
<a href = '#/course'></a>
通過上面的步驟,當我們點擊a標簽的時候,被匹配到的路由所映射的組件就會被渲染到<router-view>中
注意:上面步驟的講解主要是為了方便理解,實際應用中的vue項目通常由腳手架工具搭建,搭建的時候勾選上router,項目中就默認配置安裝好了vue-router
3.什么是單頁應用
百度百科解釋,單頁Web應用(single page web application,SPA),就是只有一張Web頁面的應用,是加載單個HTML 頁面并在用戶與應用程序交互時動態(tài)更新該頁面的Web應用程序。
4.配置路由
需求:點擊不同的菜單(首頁、課程、會員、問答),下方顯示不同的文字
首頁:App組件代碼
<template>
<div id="app">
<div class='page'>
<ul>
<li><a href="#/">首頁</a></li>
<li><a href="#/course">課程</a></li>
<li><a href="#/vip">會員</a></li>
<li><a href="#/question">問答</a></li>
</ul>
</div>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
components: {
}
}
</script>
<style scoped>
</style>
路由配置:roiter文件夾中的index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
//下面是引入的四個路由
import Home from '@/components/Home'
import Course from '@/components/Course'
import Question from '@/components/Question'
import Vip from '@/components/Vip'
// 讓vue-router作為vue的插件使用
Vue.use(VueRouter)
// 配置路由信息
const router = new VueRouter({
routes: [
{
path: '/',
component: Home
},
{
path: '/course',
component: Course
},
{
path: '/vip',
component: Vip
},
{
path: '/question',
component: Question
}
]
})
export default router
上面的代碼就可以通過點擊實現路由的跳轉了,但是a標簽的路由會在路徑前面添加一個"#",顯得特別的不優(yōu)雅,我們可以通過router-link進行優(yōu)化
5.使用router-link實現跳轉
首頁:App組件代碼
<li><router-link to="/">首頁</router-link></li>
<li><router-link to="/course">課程</router-link></li>
<li><router-link to="/vip">會員</router-link></li>
<li><router-link to="/question">問答</router-link></li>
router-link的其他配置
1.可以動態(tài)綁定一個變量
<li><router-link :to="index">首頁</router-link></li>
<li><router-link :to="course">課程</router-link></li>
<li><router-link :to="vip">會員</router-link></li>
<li><router-link :to="question">問答</router-link></li>
<script type="text/ecmascript-6">
export default {
data () {
return {
index: '/',
course: '/course',
vip: '/vip',
question: '/question'
}
}
}
</script>
2.默認router-link生成的是a標簽,可以更改成其他標簽, 使用tag來設置
<li><router-link :to="index" tag="div">首頁</router-link></li>
<li><router-link :to="course" tag="div">課程</router-link></li>
<li><router-link :to="vip" tag="div">會員</router-link></li>
<li><router-link :to="question" tag="div">問答</router-link></li>
3.設置router-link的激活樣式
第一種方式,在全局配置一個linkActiveClass
配置路由信息(在router文件夾中的index.js中添加)
const router = new VueRouter({
//設置激活樣式
linkActiveClass: 'nav-active',
routes: [
{
path: '/',
component: Home
},
......
]
})
第一種方式的優(yōu)先級小于第二種方式
第二種方式,直接在router-link上增加active-class
默認情況下是支持的點擊事件
<li><router-link :to="index" active-class="nav-active">首頁</router-link></li>
router-link 的激活樣式默認情況下的路由是模糊匹配,例如當前路徑是 /article/1 那么也會激活 ,所以當設置 exact-active-class 以后,這個 router-link 只有在當前路由被全包含匹配時才會被激活 exact-active-class 中的 class。
4.設置渲染組件的公共樣式,可以直接在router-view上增加class
<router-view class="center"></router-view>
5.可以更改切換的事件,默認是鼠標點擊切換,通過設置event實現
<li><router-link :to="index" active-class="nav-active" event="mouseover">首頁</router-link></li>
<li><router-link :to="course" event="mouseover">課程</router-link></li>
<li><router-link :to="vip" event="mouseover">會員</router-link></li>
<li><router-link :to="question" event="mouseover">問答</router-link></li>
使用router-link進行的路由跳轉執(zhí)行的都是模糊匹配,如果要實現精準匹配,需要在標簽中增加上exact屬性。
6.嵌套路由
當路由越來越多的時候,把全部路由都以平級的關系羅列在一起顯得那么的沒有邏輯,也讓路由變得難以維護,為此,我們可以讓存在上下級邏輯關系的路由組合成嵌套路由。
比如下面這種場景:點擊vip路由之后,還可以通過點擊不同的區(qū)域去展現vip路由下的“一級會員、二級會員、三級會員”路由頁面。
核心代碼:需要在vip.vue組件中增加觸發(fā)路由的 <router-link>,并且在這個頁面中放置一個<router-view>,當子路由被匹配到的時候,對應的頁面會被渲染到這里。
<template>
<div class="page">
<h1>我是vip會員頁面</h1>
<ul class="nav">
<router-link tag="li" to="/vip/one"><a>一級會員</a></router-link>
<router-link tag="li" to="/vip/two"><a>二級會員</a></router-link>
<router-link tag="li" to="/vip/three"><a>三級會員</a></router-link>
</ul>
<!--當路由匹配成功,組件one/two/three會被渲染到這里-->
<router-view></router-view>
</div>
</template>
2.在路由文件夾的index.js文件中,需要引入vip路由嵌套下的三個子路由
import One from '@/components/One'
import Two from '@/components/Two'
import Three from '@/components/Three'
同時為vip路由配置children字段
{
path: '/vip',
component: Vip,
children: [
{
path: 'one', // /vip/one
component: One
},
{
path: 'two',
component: Two
},
{
path: 'three',
component: Three
}
]
}
7.命名路由
有時候,通過一個名稱來標識一個路由顯得更方便一些,特別是在鏈接一個路由,或者是執(zhí)行一些跳轉的時候,通俗的說,命名路由就是用name屬性給路由取一個名字 例如:
在路由文件夾的index.js文件中,給'/questions'路由增添一個屬性name,屬性值為這個路由的名字 'wenda'
{
path: '/questions',
name: 'wenda', //注意這里的name值 wenda
component: Questions
},
......
在進行路由的使用這個name屬性
<li><router-link exact to="/" >首頁</router-link></li>
<li><router-link to="/course" >課程</router-link></li>
<li><router-link to="/vip" >vip</router-link></li>
<!-- 這里使用 name值 -->
<li><router-link :to="{name: 'wenda'}" >問答</router-link></li>
8.命名視圖
有時候想同時 (同級) 展示多個視圖,而不是嵌套展示,這個時候可以給視圖命名,就可以在一個路由中展示多個視圖(組件),并實現把指定的路由組件展現到指定的位置。
例如: 在home路由中增加側邊欄和主體內容兩個組件
在路由文件夾下的index.js文件中設置路由對應的組件
//新引進的兩個命名視圖
import Sider from '@/components/Sider'
import HomeContent from '@/components/HomeContent'
......
const router = new VueRouter({
linkActiveClass: 'nav-active',
routes: [
{
path: '/',
components: { //注意這里的components, default設置的組件 被渲染到 <router-view></router-view> 放置的位置
default: Home,
sider: Sider, //Sider組件被渲染到<router-view name=“sider”></router-view> 放置的位置
homecontent: HomeContent //同理
}
},
...
]
})
......
在對應的組件中渲染視圖
<template>
<div class="page">
<my-header></my-header>
<router-view></router-view>
<div class="page-main">
<router-view name="sider"></router-view>
<router-view name="homecontent"></router-view>
</div>
</div>
</template>
9.重定向
路由重定向通俗的說就是從一個路由重新定位跳轉到另一個路由,例如:訪問的 “/a” 重定向到“/b”
重定向也是通過配置routes選項完成的
routes: [
{
path: '/course',
component: Course
},
{
path: '/hello',
component: Hello,
redirect: '/course'
}]
上面代碼中,訪問 ‘/hello’ 并不會去渲染Hello組件,而是會跳轉到路由‘/course’,去渲染course組件
重定向的目標可以是一個命名路由
routes: [
{
path: '/questions',
name: 'wenda',
component: Questions
},
{
path: '/hello',
component: Hello,
redirect: {name: 'wenda'}
}]
上面代碼配置后,訪問 ‘/hello’就會跳轉到命名路由‘wenda’,即‘/questions’,從而去渲染Questions組件
重定向的目標也可以是一個方法,在方法中可以寫一些邏輯代碼
{
path: '/hello',
component: Hello,
redirect: (to) => {
if (to.hash) {
return '/questions'
} else {
return '/course'
}
}
}
當路徑參數對象存在hash值的時候,路由會被跳轉到/questions,否則會被跳轉到/course
10.別名
別名從字面上理解為別的名字,比如有的人有一個中文名,還有一個別的名字英文名。舉例: ‘/hello’ 有一個別名 ‘/hi’, 當用戶訪問‘/hi’的時候,url會保持不變,但是渲染的還是'/hello'對應的組件,說白了就是不管用戶訪問的是'/hello',還是‘/hi’,找到的都是同一個人(Hello組件)
routes: [
{
path: '/hello',
component: Hello,
alias: '/hi'
}]
11.編程式導航
首先需要說一下聲明式導航,前面我們學過的通過定義導航鏈接的這種方式叫做聲明式導航,特點就是要在template中去寫跳轉鏈接,通過生成a標簽的形勢跳轉
<ul>
<li><router-link :to="index" active-class="nav-active" event="mouseover">首頁</router-link></li>
<li><router-link :to="course" event="mouseover">課程</router-link></li>
<li><router-link :to="vip" event="mouseover">會員</router-link></li>
<li><router-link :to="question" event="mouseover">問答</router-link></li>
</ul>
編程式導航
編程式導航通俗的說就是vue-router給我們提供了一堆方法,我們通過在js中編寫代碼來實現導航切換,這些常用方法包括:back、forward、go、push、replace等
push
想要導航到不同的URL,則使用 router.push方法。這個方法會向 history 棧添加一個新的記錄
pushHandle () {
// this.$router.push('/hello')
// push內部可以給對象
this.$router.push({name: 'wenda'})
}
注意: 在 Vue 實例內部,你可以通過 $router 訪問路由實例
replace
跟 router.push 很像,唯一的不同就是,它不會向 history 添加新記錄,而是跟它的方法名一樣 —— 替換掉當前的 history 記錄
back
back方法可以回到上一步
forward
forward方法可以前進一步
go
go方法可以一次跳多步
注意:go里面如果是正數表示前進,如果是負數表示后退
下面代碼代表表示前進2步
goHandle () {
this.$router.go(2)
}
12.動態(tài)路由匹配
動態(tài)路由意味著不固定,具有某種模式,我們希望通過某種匹配方式,把這種不固定的路由形勢映射到同一個組件,例如:一個User組件,不同的ID表示不同的用戶,即/user/1、/user/2、/user/3,這些不同用戶所對應的路由,我們都希望用一個User組件來渲染。vue-router中提供了動態(tài)路徑參數來實現這種需求,動態(tài)路徑參數寫法:
routes: [
// 動態(tài)路徑參數 以冒號開頭
{
path: '/user/:id',
component: User
}
]
這里的id類似于一個變量,id可以是1、2、3等具體的值
聲明式導航:
<template>
<div class="page">
<router-link :to="'/user/'+item.id" v-for="(item, index) in userList" :key="index">{{item.username}}</router-link>
</div>
</template>
編程式導航:
goToDetail(item) {
this.$router.push({
name: `Detail`,
params: {
id: item.id
}
});
}
路由配置:
?用的是正則表達式,?代表零次或者一次,如果不加問號的話,則id值必須傳
routes: [
{
path: '/user/:id?',
component: User
}
]
如何監(jiān)聽/響應動態(tài)參數的變化?
方式1: 使用 beforeRouteUpdate 鉤子函數
beforeRouteUpdate (to, from, next) {
//to和$route的信息差不多
this.userInfo = this.userList.filter((item) => to.params.id === item.id)[0]
next()
}
方式2: 在組件中對 $route 進行 watch(監(jiān)聽)
watch: {
$route () {
console.log(this.$route)
}
}
路由信息對象$route解析:
- path 對應當前路由的路徑
- params 動態(tài)路由參數
- query url查詢參數
- hash 當前路由的hash值
- fullPath 完整的url路徑,包含查詢參數和hash
- matched 包含當前路由的所有嵌套路徑片段的路由記錄
- name 當前路由的名稱
13.路由組件傳參
路由和對應組件之間的傳參:
在組件中使用 $route 會使之與其對應路由形成高度耦合,從而使組件只能在某些特定的 URL 上使用,限制了其靈活性,我們需要做的是通過傳參將組件與路由解耦,使得組件的使用更加靈活,這里需要使用到props
路由配置里面我們需要改成這樣
只要是對應的路由中設置了props: true,動態(tài)路由參數就會自動作為一個屬性,傳到對應的組件中去,在組件中用porps進行接收之后就可以通過this.屬性來使用動態(tài)路由中的參數
routes: [
{
path: '/user/:id?',
component: User,
props: true
}
]
在組件的js代碼中通過props接收
props: ['id'],
14.記錄滾動位置
在路由配置文件中通過以下代碼,當導航到新路由時,通過設置滾動行為讓頁面滾動到你想要的位置。
const router = new VueRouter({
routes: [...],
scrollBehavior (to, from, savedPosition) {
//to-->即將進入的路由
//from--->從哪里來
//savePosition--->保存滾動的位置信息
// 如果檢測到記錄的位置信息,我們就返回這個位置信息
//如果沒有檢測到記錄的位置信息,我們就返回頂部
if(savePositon){
return savePositon
}else{
return {x:0,y:0}
}
}
}
注意:
這個功能只在支持 history.pushState 的瀏覽器中可用,和mode沒有關系。
高版本的瀏覽器可以不用寫上面那些代碼,可以自動實現。
15.vue-router中的全局鉤子函數
在vue-router中,路由發(fā)生變化,我們可以做一些事情,例如:可以決定是否進入導航,可以決定跳轉到哪里,官方文檔中又叫做導航守衛(wèi)。
首先來看一個全局的鉤子函數,官方文檔中叫做注冊一個全局的前置守衛(wèi),使用router.beforeEach方法來實現
router.beforeEach(() => {
console.log('beforeEach執(zhí)行了....')
})
這里的beforeEach可以理解為在每個導航進入之前掛的一個鉤子,會在每個導航進入之前出發(fā),在beforeEach里面就可以做一些事情,例如,阻止進入導航,執(zhí)行上面的代碼,會發(fā)現我們點擊相應的導航,對應的組件并不能渲染出來了,罪魁禍首就是這個beforeEach。
當我們把代碼稍作修改:
router.beforeEach((to, from, next) => {
console.log('beforeEach執(zhí)行了....')
next()
})
組件就可以正常渲染了。
每個路由鉤子函數接收三個參數:
to: [Route]: 即將要進入的目標 路由對象
from: [Route]: 當前導航正要離開的路由
next: [Function]: 一定要調用該方法來 resolve 這個鉤子
這里的next是一個函數,如果不調用next方法,就不會進入下一個鉤子,我們就可以用它來實現跳轉或者取消
在寫具體跳轉或者取消案例之前,插播一個前置知識點:路由元信息
路由元信息就是給每條路由記錄配置一個meta字段,字段配置好后可以在需要的地方拿出來使用
配置示例:
{
path: '/',
components: {
default: Home,
a: HomeSider,
b: HomeMain
},
//上面的這個對象稱為一個路由記錄
//meta我們設置一個全局的,也可以在單個的路由記錄中單個設置
meta: {
isLogin: true
}
}
我們可以從鉤子函數的參數中拿到meta字段值
router.beforeEach((to, from, next) => {
console.log('beforeEach執(zhí)行了....')
if (to.meta.isLogin) {
next()
} else {
next(false)
}
})
next函數中傳入false就表示不進入導航,我們在meta字段中配置了isLogin,在使用的時候通過to.meta.isLogin 取出來做判斷,如果值是true就執(zhí)行next 如果值是false就執(zhí)行next(false)
next函數內還可以傳入一個路由地址,會自動跳到改地址,我可以把上面代碼稍作修改
router.beforeEach((to, from, next) => {
console.log('beforeEach執(zhí)行了....')
if (to.meta.isLogin) {
next()
} else {
next('/login')
}
})
除了在導航進入之前有一個鉤子函數,在導航進入之后也有一個鉤子函數,叫做afterEach,使用方法和beforeEach類似, 因為afterEach執(zhí)行時已經進入到導航了,所以沒有第三個參數next
router.afterEach((to, from) => {
console.log('afterEach執(zhí)行了....')
// 判斷是否有title字段
if (to.meta.title) {
window.document.title = to.meta.title
} else {
window.document.title = 'hello'
}
})
16.vue-router中寫到路由記錄里的鉤子函數
beforeEnter 在進入導航前被調用,需要在路由記錄里面配置
{
path: '/course',
component: Course,
meta: {
isLogin: false,
title: '好好學編程'
},
beforeEnter (to, from, next) {
console.log('beforeEnter被執(zhí)行了')
}
},
17.寫在組件內部的路由鉤子函數
1.beforeRouteEnter, 在導航進入前被調用,在這個函數里面不能拿到this,因為即將被渲染的組件還沒被創(chuàng)建
beforeRouteEnter (to, from, next) {
console.log('user組件中的beforeRouteEnter執(zhí)行了')
next()
}
2.beforeRouteUpdate,在當前路由改變,但是該組件被復用時調用,舉例來說,對于一個帶有動態(tài)參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,由于會渲染同樣的 Foo 組件,因此組件實例會被復用。而這個鉤子就會在這個情況下被調用。 可以訪問組件實例 this
beforeRouteUpdate (to, from, next) {
console.log('user組件中的beforeRouteUpdate執(zhí)行了')
next()
}
3.beforeRouteLeave,導航離開該組件的對應路由時調用,可以訪問組件實例 this
beforeRouteLeave (to, from, next) {
console.log('user組件中的beforeRouteLeave執(zhí)行了')
next()
}
18.路由切換的動畫效果
vue中封裝了一套transtion組件,可以提供過渡效果
<transition>
<router-view></router-view>
</transition>
通過過渡css類名的方式來設置過渡效果
過渡的類名稱有:
- v-enter:定義進入過渡的開始狀態(tài)。在元素被插入之前生效,在元素被插入之后的下一幀移除。
- v-enter-active:定義進入過渡生效時的狀態(tài)。在整個進入過渡的階段中應用,在元素被插入之前生效,在過渡/動畫完成之后移除。這個類可以被用來定義進入過渡的過程時間,延遲和曲線函數。
- v-enter-to: 2.1.8版及以上 定義進入過渡的結束狀態(tài)。在元素被插入之后下一幀生效 (與此同時 v-enter 被移除),在過渡/動畫完成之后移除。
- v-leave: 定義離開過渡的開始狀態(tài)。在離開過渡被觸發(fā)時立刻生效,下一幀被移除。
- v-leave-active:定義離開過渡生效時的狀態(tài)。在整個離開過渡的階段中應用,在離開過渡被觸發(fā)時立刻生效,在過渡/動畫完成之后移除。這個類可以被用來定義離開過渡的過程時間,延遲和曲線函數。
- v-leave-to: 2.1.8版及以上 定義離開過渡的結束狀態(tài)。在離開過渡被觸發(fā)之后下一幀生效 (與此同時 v-leave 被刪除),在過渡/動畫完成之后移除。
其中,v- 這個前綴是可以自定義的,例如:
.fade-enter {
transform: translateX(-100%);
opacity: 0;
}
.fade-enter-to {
transform: translateX(0);
opacity: 1;
}
.fade-enter-active {
transition: 1s;
}
.fade-leave {
transform: translateX(0);
opacity: 1;
}
.fade-leave-to {
transform: translateX(100%);
opacity: 0;
}
.fade-leave-active{
transition: 1s;
}
我們把類名稱的前綴自定義成了“fade-”, 這里需要注意的是前綴可以自定義,但是后面的enter、enter-to不能自定義,自定義類名稱后,需要在transition組件上加name屬性
<transition mode="out-in" name="fade">
<router-view></router-view>
</transition>
上面代碼中,我們發(fā)現有個mode屬性,這個屬性表示設置過渡的模式, out-in,通俗的說就是先離開,再進入,同時還有另一種模式,in-out,先進入,再離開