詳解Vue-router

本文目錄:

  • 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,先進入,再離開

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容