1小時(shí) Vue Router 從入門(mén)到放棄

? 本文所用項(xiàng)目 GitHub 地址:https://github.com/trp1119/vue-router

? 本文與 Vue Router 官方文檔 區(qū)別:非官方文檔功能羅列旱函,而是從實(shí)際應(yīng)用角度一步步進(jìn)行 Vue Router 設(shè)置及功能介紹芽唇。水平有限各淀,難免存有紕漏姿现,歡迎在評(píng)論區(qū)指正交流井辜。

前言

? 現(xiàn)在做前端 Web App,路由是必不可缺的功能兼都。以前網(wǎng)站開(kāi)發(fā)漂羊,由鏈接跳轉(zhuǎn)到后端,進(jìn)行模板渲染侣背,產(chǎn)生一個(gè)新的 HTML 返回給瀏覽器端白华,等瀏覽器顯示出頁(yè)面慨默,完成一次路由跳轉(zhuǎn)。而對(duì)于現(xiàn)在的單頁(yè)面應(yīng)用開(kāi)發(fā)弧腥,頁(yè)面跳轉(zhuǎn)不經(jīng)過(guò)后端服務(wù)器厦取,頁(yè)面渲染內(nèi)容全部來(lái)自于JavaScript。既然路由跳轉(zhuǎn)由前端來(lái)做鸟赫,則需要稱(chēng)職合理的工具處理前端路由蒜胖。

? 現(xiàn)在基本上每個(gè)前端框架都會(huì)配備路由管理工具,像 Vue 使用的 Vue Router抛蚤,React 使用的 React Router台谢,還有不和框架耦合的 History 等工具。這些工具岁经,在前端 SAP 開(kāi)發(fā)中起著越來(lái)越重要的作用朋沮。

? 什么是 Vue RouterVue RouterVue.js 官方的路由管理器缀壤。通過(guò)將組件映射到路由 routes樊拓,然后使用 Vue Router 進(jìn)行渲染,實(shí)現(xiàn)路由功能塘慕。

? 本文 Vue Router 基于模塊化工程使用筋夏。在使用之前,需要先安裝 vue-router 插件图呢。

npm i vue-router -S
1 Vue Router 之集成

? vue-router 插件安裝完畢后条篷,需要進(jìn)行路由的部署。在 src 文件夾下 創(chuàng)建 router 文件夾并創(chuàng)建 router.jsroutes.js 文件蛤织。

? 為什么分開(kāi)配置赴叹?因?yàn)樵陧?xiàng)目變龐大之后,路由配置會(huì)非常多指蚜,所以可以單獨(dú)配置一個(gè)和路由映射關(guān)系有關(guān)的文件 routes.js乞巧,而 router.js 主要進(jìn)行路由器 router 的內(nèi)容配置。

1.1 在 routes.js 中配置路由映射關(guān)系

? export default 一個(gè)數(shù)組摊鸡,數(shù)組中的每個(gè)對(duì)象都是一個(gè)路由項(xiàng)绽媒。

import Login from '../view/login' // 1.引入組件
import Home from '../view/home'

export default [ // 4.導(dǎo)出路由映射關(guān)系
  {
    path: '/login', // 2.設(shè)置跳轉(zhuǎn)路由
    component: Login // 3.映射組件
  },
  {
    path: '/home',
    component: Home
  }
]

? 不推薦這么使用,因?yàn)檫@樣每次在全局 import這個(gè) router 的時(shí)候免猾,引入的都是同一個(gè) router些椒,如果需要每次引入的時(shí)候新創(chuàng)建一個(gè) router,這種方式是做不到的掸刊。

? 另外,由于項(xiàng)目需要服務(wù)端渲染赢乓。每次 export default 同一個(gè) router忧侧,會(huì)導(dǎo)致在服務(wù)端渲染時(shí)出現(xiàn)內(nèi)存溢出的問(wèn)題石窑。每次服務(wù)端渲染都會(huì)重新生成一個(gè)新的 app,由于 router 只有一個(gè)對(duì)象(共用同一個(gè))蚓炬,在服務(wù)端渲染流程結(jié)束后松逊,app 對(duì)象沒(méi)有釋放,每次都會(huì)緩存新的 app肯夏,導(dǎo)致內(nèi)存沒(méi)有下降经宏,一直處于高點(diǎn),隨著內(nèi)存逐漸累加驯击,出現(xiàn)內(nèi)存溢出烁兰。

1.2 默認(rèn)路由跳轉(zhuǎn)

? 在路由配置文件 routes.js 中配置默認(rèn)路由跳轉(zhuǎn)。

export default [
  {
    path: '/', // 根路徑
    redirect: '/login' // 默認(rèn)跳轉(zhuǎn)路由
  },
  {
    path: '/login',
    component: Login
  },
  {
    path: '/home',
    component: Home
  }
]
1.3 在 route.js 中配置路由器

1.3.1 配置方法1

import Router from 'vue-router' // 1.引入 Vue Router 插件中 Router 路由器
import routes from './routes' // 2.引入路由映射關(guān)系

export default new Router({ // 4.創(chuàng)建并導(dǎo)出 Router 對(duì)象實(shí)例
  routes // 3.傳入映射關(guān)系配置
})

1.3.2 配置方法2

import Router from 'vue-router' // 1.引入 Vue Router 插件中 Router 路由器
import routes from './routes' // 2.引入路由映射關(guān)系

export default () => { // 4.創(chuàng)建并導(dǎo)出 Router 方法(注意這里導(dǎo)出的是方法徊都,并沒(méi)有在此創(chuàng)建對(duì)象實(shí)例)
  return new Router({
    routes // 3.傳入映射關(guān)系配置
  })
}

? 每次生成新的 Router 對(duì)象實(shí)例沪斟,渲染結(jié)束同 app 一起釋放,不會(huì)出現(xiàn)內(nèi)存溢出問(wèn)題暇矫。

1.4 在入口文件 main.js 中注入路由功能

? 引入 VueRouter 插件并使用(Vue.use())以使用路由功能主之,引入前面配置好的 Router 方法并使用以使用路由設(shè)置及映射關(guān)系。

import Vue from 'vue'
import VueRouter from 'vue-router' // 引入 VueRouter 路由插件

import App from './App.vue'

import createRouter from './router/router' // 引入帶映射關(guān)系的 Router 方法

Vue.config.productionTip = false

Vue.use(VueRouter) // 使用 VueRouter 插件
const router = createRouter() // 在此創(chuàng)建 router 對(duì)象

new Vue({
  router, // 注入路由李根。通過(guò)在根節(jié)點(diǎn) Vue 實(shí)例上掛載 router 對(duì)象槽奕,使每個(gè)組件都能拿到這個(gè) router 對(duì)象,從而讓整個(gè)應(yīng)用都有路由功能房轿。(VueRouter內(nèi)部實(shí)現(xiàn)此功能)
  render: h => h(App),
}).$mount('#app')
1.5 使用 router-view 渲染匹配到的組件

? 在 App.js 中渲染頁(yè)面粤攒。

<template>
  <div id="app">
   <!-- 路由出口 -->
   <!-- 路由匹配到的組件將渲染在這里 -->
    <router-view />
  </div>
</template>
1.6 使用 router-link 進(jìn)行頁(yè)面跳轉(zhuǎn)

? router-link 的實(shí)現(xiàn)是 a 標(biāo)簽。點(diǎn)擊對(duì)應(yīng)鏈接后會(huì)在 <router-view /> 中渲染路由匹配到的組件冀续。

? 頁(yè)面中可點(diǎn)擊的路由一般都會(huì)通過(guò) router-link琼讽,因?yàn)?router-link 的實(shí)現(xiàn)是 a 標(biāo)簽,a 標(biāo)簽中的 href 有利于網(wǎng)站的 SEO洪唐,但 a 標(biāo)簽?zāi)J(rèn)的行為是頁(yè)面跳轉(zhuǎn)钻蹬,而不是前端路由跳轉(zhuǎn)。即 router-link 不單純是 a 標(biāo)簽的實(shí)現(xiàn)凭需,而是通過(guò)內(nèi)部事件问欠,實(shí)現(xiàn)前端路由跳轉(zhuǎn)。

<template>
  <div id="app">
    <router-link to="/login">去Login頁(yè)</router-link>
    <router-link to="/home">去Home頁(yè)</router-link>
    <!-- 組件渲染 -->
    <router-view />
  </div>
</template>
1-6.png
1.7 Vue Router 基礎(chǔ)集成設(shè)置完畢

? 設(shè)置完畢粒蜈,在頁(yè)面打開(kāi)路由顺献。可以發(fā)現(xiàn) Vue Router 自動(dòng)在網(wǎng)站域名后添加了 #/ 枯怖,這是因?yàn)?Vue Router 默認(rèn)的路由形式是使用哈希路由注整。作為 SAP 且有服務(wù)端渲染的情況下,路由改為 histiory 形式(無(wú) #/)更為合理且更利于 SEO 優(yōu)化。

1-7.png
2 Vue Router 之配置

? 創(chuàng)建 router 實(shí)例時(shí)常用參數(shù)配置及作用肿轨。

2.1 mode配置

? Vue Router 默認(rèn)使用哈希路由(路由中帶 #)寿冕,但哈希路由一般用來(lái)定位,而不是做路由狀態(tài)的記錄椒袍。同時(shí)驼唱,哈希路由不會(huì)被搜索引擎解析,影響網(wǎng)站 SEO 驹暑。所以在服務(wù)端渲染時(shí)玫恳,一般不使用哈西路由。

? 使用 history 路由优俘,可在路由器配置文件 route.js 中配置 mode京办。mode 有兩種參數(shù),一個(gè)是默認(rèn)的 hash 兼吓,一個(gè)是 history臂港。

export default () => {
  return new Router({
    routes, // 路由配置項(xiàng)
    // mode: 'hash', // 默認(rèn)哈西路由 
    mode:'history',  // 配置 hisyory 路由
  })
}
2-1-1.png
2-1-2.png
2.2 base 配置

? 在 routes.js 配置的所有路由前天添加 /自定義base/,這個(gè)路徑作為所有應(yīng)用的基路徑视搏。在應(yīng)用中不論是用 route-link 還是 route 對(duì)象跳轉(zhuǎn)审孽,只要是通過(guò) vue routerapi 跳轉(zhuǎn),都會(huì)加上此基路徑浑娜。但是把路徑中 /base/ 手動(dòng)去掉佑力,仍然會(huì)顯示,所有 base 不是強(qiáng)制性的筋遭。在區(qū)分頁(yè)面路徑和其他類(lèi)型路徑的時(shí)候會(huì)用到打颤。

? 在 mode 配置為 hash 時(shí),base 配置不生效漓滔。

export default () => {
  return new Router({
    routes,
    mode:'history',
    base: '/mybase/', // 注意加前后/编饺,base 在 mode 配置為 hash 時(shí)不生效
  })
}
2.3 linkActiveClass 與 linkExactActiveClass 配置

? 查看 1.5 中配置的 route-link 瀏覽器解析源碼,會(huì)發(fā)現(xiàn)激活的路由默認(rèn)添加 router-link-exact-activerouter-link-active 樣式响驴,可以在 linkActiveClasslinkExactActiveClass 中自定義樣式名稱(chēng)透且,然后在 css 中自定義全局樣式。

2-3-1.png
export default () => {
  return new Router({
    routes,
    mode:'history',
    base: '/mybase/',
    linkActiveClass: 'active-link', // 配置 route-link 鏈接 class豁鲤,路徑不完全匹配時(shí)添加 class 為 linkActiveClass
    linkExactActiveClass: 'exact-active-link', // 路徑完全匹配時(shí)添加 class 為 linkExactActiveClass linkActiveClass
  })
}

? 配置完畢秽誊,可以看到 a 標(biāo)簽 class 樣式已經(jīng)變?yōu)榕渲脴邮健?/p>

2-3-2.png

? 那么 linkActiveClasslinkExactActiveClass 有什么區(qū)別?

? 展示區(qū)別前琳骡,先在 routes.jsapp.vue 中補(bǔ)充路由锅论。

// routes.js
export default [
  {
    path: '/',
    redirect: '/login'
  },
  {
    path: '/login',
    component: Login
  },
  {
    path: '/home',
    component: Home
  },
  {
    path: '/home/exact', // 補(bǔ)充路由
    component: Home
  }
]
<!-- app.vue -->
<template>
  <div id="app">
    <router-link to="/login">去Login頁(yè)</router-link>
    <router-link to="/home">去Home頁(yè)</router-link>
    <!-- 補(bǔ)充鏈接 -->
    <router-link to="/home/exact">去Home/exact頁(yè)</router-link>
    <!-- 組件渲染 -->
    <router-view />
  </div>
</template>

? 補(bǔ)充完畢,點(diǎn)擊“去Home/exact頁(yè)”后楣号,查看瀏覽器源碼最易,會(huì)發(fā)現(xiàn) “去Home頁(yè)”路由少了 my-exact-active-link 樣式怒坯,但仍保留 my-active-link 樣式。即路徑不完全匹配時(shí)添加 class 為 my-active-linklinkActiveClass 中配置的樣式)耘纱,路徑完全匹配時(shí)添加 class 為 my-exact-active-link my-active-linklinkExactActiveClasslinkActiveClass 中配置的樣式)敬肚。

2-3-3.png
2.4 scrollBehavior 配置

? scrollBehavior 用于配置頁(yè)面跳轉(zhuǎn)時(shí)是否滾動(dòng),scrollBehavior 接收一個(gè)方法束析,有三個(gè)參數(shù) tofrom憎亚、savePosition员寇,其中,參數(shù) to 為去的路由第美,from 跳轉(zhuǎn)到 to 路由之前的路由蝶锋。如果之前進(jìn)入過(guò)這個(gè)路由,savePosition 用于保存之前滾動(dòng)條滾動(dòng)的位置什往。to扳缕、from 不是字符串,而是完整的 router 的對(duì)象别威,包含路由的 params躯舔、query 等信息。

export default () => {
  return new Router({
    routes,
    mode:'history',
    base: '/mybase/',
    linkActiveClass: 'active-link',
    linkExactActiveClass: 'exact-active-link',
    scrollBehavior (to, from, savePosition) { // 頁(yè)面跳轉(zhuǎn)時(shí)是否需要滾動(dòng)
      // to 去往路由 from 來(lái)時(shí)路由 savePosition 記錄滾動(dòng)條位置
      if (savePosition) {
        return savePosition // 如果進(jìn)入過(guò)省古,回到之前的位置
      } else {
        return { x: 0, y: 0 } // 如果未因如果粥庄,滾動(dòng)到原點(diǎn)
      }
    },
  })
}
2.5 parseQuery 與 stringifyQuery

? 例如 http://localhost/login?name=zhangsan&password=12345url 后帶的參數(shù) queryname=zhangsan&password=12345string 格式豺妓,需轉(zhuǎn)為 JSON Object惜互,Vue 是默認(rèn)做轉(zhuǎn)換的,但如果有默認(rèn)需求琳拭,可通過(guò)配置 parseQuery 進(jìn)行轉(zhuǎn)換训堆。將 Object 轉(zhuǎn)為 stiring 可在 stringifyQuery 中配置。

export default () => {
  return new Router({
    routes,
    mode:'history',
    base: '/mybase/',
    linkActiveClass: 'active-link',
    linkExactActiveClass: 'exact-active-link',
    scrollBehavior (to, from, savePosition) {
      if (savePosition) {
        return savePosition
      } else {
        return { x: 0, y: 0 }
      }
    },
    parseQuery (query) {},
    stringifyQuery (obj) {},
  })
}
2.6 fallback配置

? 并不是所有瀏覽器都支持 history 前端路由(頁(yè)面不跳轉(zhuǎn)但內(nèi)容切換)白嘁,在不支持 history 前端路由的瀏覽器中坑鱼,Vue 自動(dòng) fallback hash 路由模式,如果不希望 Vue 進(jìn)行此操作权薯,可將 fallback 設(shè)置為 false姑躲。當(dāng) fallbackfalse 時(shí),Vue 不會(huì)去自動(dòng)處理盟蚣,在不支持 histiory 路由的瀏覽器中黍析,單頁(yè)面應(yīng)用就變?yōu)槎囗?yè)面應(yīng)用,每次頁(yè)面跳轉(zhuǎn)都會(huì)去后端請(qǐng)求數(shù)據(jù)返回內(nèi)容屎开,耗時(shí)阐枣。

export default () => {
  return new Router({
    routes,
    mode:'history',
    base: '/mybase/',
    linkActiveClass: 'active-link',
    linkExactActiveClass: 'exact-active-link',
    scrollBehavior (to, from, savePosition) {
      if (savePosition) {
        return savePosition
      } else {
        return { x: 0, y: 0 }
      }
    },
    parseQuery (query) {},
    stringifyQuery (obj) {},
    fallback: true,
  })
}
3 route 配置及參數(shù)傳遞
3.1 name 配置

? 使用 name 對(duì)路由進(jìn)行命名,和 pathcomponent 的命名無(wú)關(guān)聯(lián)蔼两,可以使用這個(gè) name 進(jìn)行路由跳轉(zhuǎn)甩鳄。

// routes.js
export default [
  //...
  {
    path: '/login',
    component: Login,
    name: Login, // name 命名
  },
  //...
]

? 在路由跳轉(zhuǎn)配置中,name 傳入的是 JSON Object额划,希望 Vue 去解析它而不是當(dāng)做 stirng 處理妙啃,所以需要使用 v-bind 進(jìn)行數(shù)據(jù)綁定

<!-- app.vue -->
<template>
  <div id="app">
    <router-link to="/login">去Login頁(yè)</router-link>
   <!-- name 形式路由 -->
    <router-link :to="{name: 'login'}">去Login頁(yè)(name 形式)</router-link> 
    <router-link to="/home">去Home頁(yè)</router-link>
    <router-link to="/home/exact">去Home/exact頁(yè)</router-link>
    <!-- 組件渲染 -->
    <router-view />
  </div>
</template>
3.2 meta 配置

? meta 用于保存路由信息,

? 在 html head 標(biāo)簽中會(huì)使用 meta 保存頁(yè)面元信息俊戳,這些信息有利于 SEO 優(yōu)化揖赴。在寫(xiě) Vue 組件的時(shí)候,很難寫(xiě)入這些信息抑胎,則可在路由配置中加入 meta燥滑,這些信息,可以在拿到路由 route 對(duì)象時(shí)通過(guò) .mate 拿到這些信息并進(jìn)行設(shè)置阿逃。

// routes.js
export default [
  //...
  {
    path: '/login',
    component: Login,
    name: Login,
    meta: { // meta 配置
      title: 'This is Home Page',
      description: 'This is Home Page description'
    },
  },
  //...
]
3.3 children 嵌套路由配置

? children 也是個(gè)數(shù)組铭拧,是子路由,配置和父級(jí)路由配置相同恃锉。

// routes.js
export default [
  //...
  {
    path: '/login',
    component: Login,
    name: Login,
    meta: { // meta 配置
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [ // 子路由(嵌套路由)搀菩,路由匹配的內(nèi)容都是通過(guò) <route-view />展示的,/login 下的 children子路由淡喜,則其 <route-view /> 在父級(jí)路由組件 Login 中顯示秕磷。
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
  },
  //...
]

? 在 login.vue 中加入 <route-view />

<!-- login.vue -->
<template>
  <div>
    <div>Login頁(yè)內(nèi)容</div>
    <!-- 展示子路由內(nèi)容 -->
    <router-view /> 
  </div>
</template>
3-3.png
3.4 transition 過(guò)渡動(dòng)畫(huà)

? 使用 transition 包裹 <router-view /> ,并進(jìn)行動(dòng)畫(huà)樣式設(shè)置炼团。如果包裹根頁(yè)面(App.vue)中的 <router-view />澎嚣,會(huì)為每個(gè)路由切換都添加過(guò)渡動(dòng)畫(huà)。想要某個(gè)頁(yè)面使用切換效果瘟芝,使用 transition 包裹單個(gè)組件的 <router-view /> 即可易桃。

<!-- app.vue-->
<template>
  <div id="app">
    <router-link to="/login">去Login頁(yè)</router-link>
    <router-link :to="{name: 'login'}">去Login頁(yè)(name 形式)</router-link>
    <router-link to="/home">去Home頁(yè)</router-link>
    <router-link to="/home/exact">去Home/exact頁(yè)</router-link>
    <!-- 路由動(dòng)畫(huà)-->
    <transition name="fade">
      <router-view />
    </transition>
  </div>
</template>

<!-- ...-->

<style>
/*
    ...
*/
/*動(dòng)畫(huà)樣式設(shè)置*/
/* fade為自己命名的name,后綴為Vue要求寫(xiě)法 */
.fade-enter-active .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter .fade-leave-to {
  opacity: 0;
}
</style>
3.5 :id 動(dòng)態(tài)傳參

? path: '/login/:id'锌俱,動(dòng)態(tài)綁定 id晤郑,當(dāng)頁(yè)面路徑為 /login/123 時(shí),則 id123贸宏,在頁(yè)面中通過(guò) this.$route.params 可以拿到鍵值對(duì)造寝。

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    component: Login,
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
  },
  //...
]
<!-- app.vue-->
<template>
  <div id="app">
    <!-- 路由中的 id 及為鏈接中的 123-->
    <router-link to="/login/123">Login123</router-link>
    <router-link to="/login">去Login頁(yè)</router-link>
    <router-link :to="{name: 'login'}">去Login頁(yè)(name 形式)</router-link>
    <router-link to="/home">去Home頁(yè)</router-link>
    <router-link to="/home/exact">去Home/exact頁(yè)</router-link>
    <transition name="fade">
      <router-view />
    </transition>
  </div>
</template>

<script>
export default {
  mounted () {
    console.log(this.$route) //打印 this.$route 對(duì)象
  }
}
</script>

? 頁(yè)面路徑 http://localhost:8080/mybase/login/123?name=zhangsan&password=123456

? this.$route 對(duì)象打印結(jié)果:

3-5.png

? 可以看出,路由 path 中不會(huì)出現(xiàn) router.js 中設(shè)置的 base吭练,參數(shù)以 json 對(duì)象的形式存放在 query 中诫龙。

3.6 props

? 定義 propstrue 后,可以將 :id 作為 props 傳入組件 Login 中鲫咽,即在組件中签赃,用 props 直接接收即可, props: ['id']谷异,代替父組件傳值。這種方式可以實(shí)現(xiàn)在組件內(nèi)不需要寫(xiě) this.$route 而用 props 直接接收。

? 如果組件中寫(xiě)了 this.$route 這種寫(xiě)法,路由與組件耦合在一起族壳,組件就不能單獨(dú)拿去復(fù)用(因?yàn)榻M件綁定了路由),可能會(huì)存在路由不匹配尺上。如果用 props 聲明,在其他地方也可以使用這個(gè)組件史飞,因?yàn)?依賴(lài)的 id 值可以改為通過(guò)父組件傳入尖昏,不再依賴(lài)路由讀取,實(shí)現(xiàn)解耦构资。

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    props: true,
    component: Login,
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
  },
  //...
]
<!-- login.vue -->
<template>
  <div>
    <div>Login頁(yè)內(nèi)容</div>
    <router-view />
  </div>
</template>

<script>
export default {
  props: ['id'],
  mounted () {
    console.log(this.id) // 可以直接在控制臺(tái)打印出 123
  }
}
</script>

? 路由中 props 配置除了從 path 中取參數(shù),也可以自己定義內(nèi)容陨簇,這時(shí)吐绵,頁(yè)面 props 中接收的內(nèi)容即為 路由 props 中設(shè)置的值。

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    props: {
      id: '456',
      sex: 'man'
    },
    component: Login,
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
  },
  //...
]
<!-- login.vue -->
<template>
  <div>
    <div>Login頁(yè)內(nèi)容</div>
    <router-view />
  </div>
</template>

<script>
export default {
  props: ['id', 'sex'],
  mounted () {
    console.log(this.id, this.sex) // 可以直接在控制臺(tái)打印出 456 河绽,man
  }
}
</script>

? 路由 props 也可以從路由中取值己单,例如取路由 query 中的值,這樣耙饰,頁(yè)面就無(wú)需采用 this.$route.query.xxx 方式去取值纹笼。

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    props: (route) => ({name:route,query.name}), // 這里的 route 相當(dāng)于組件中的 this.$route
    component: Login,
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
  },
  //...
]

? 推薦不要拘泥于 this.$route 寫(xiě)法,盡量實(shí)現(xiàn)組件與路由解耦苟跪,以提高組件復(fù)用性廷痘。

4 高級(jí)功能
4.1 命名視圖

? 前面寫(xiě)的一個(gè)頁(yè)面中只有一個(gè)路由出口 <route-view />,但如果同一個(gè)頁(yè)面中有兩部分件已,在不同的路由下顯示不同的內(nèi)容笋额,這時(shí)可在同一個(gè)組件內(nèi)部使用兩個(gè) <route-view /> ,并對(duì)其進(jìn)行命名篷扩,對(duì)于不同的 <route-view />兄猩,在不同的名字下賦予不同的組件。

? 在路由項(xiàng)配置文件 routes.js 中鉴未,使用 components 分配不同的組件枢冤。

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    props: {
      id: '456',
      sex: 'man'
    },
    components: {
        default: Login, // 未命名,默認(rèn)使用 default
        myRouteView: Home // 不可采用 my-route-view 形式
    },
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
  },
  //...
]
<!-- app.vue-->
<template>
  <div id="app">
    <router-link to="/login/123">Login123</router-link>
    <router-link to="/login">去Login頁(yè)</router-link>
    <router-link :to="{name: 'login'}">去Login頁(yè)(name 形式)</router-link>
    <router-link to="/home">去Home頁(yè)</router-link>
    <router-link to="/home/exact">去Home/exact頁(yè)</router-link>
    <transition name="fade">
      <router-view />
    </transition>
    <!-- 注意:transition 只能包裹單頁(yè)元素铜秆,不可兩個(gè) router-view 在同一個(gè) transition 內(nèi) -->
    <!-- 不同名字的 <router-view /> -->
    <!-- 不可采用 my-route-view 形式 -->
    <router-view name="myRouteView" /> 
  </div>
</template>
4-1.png
4.2 導(dǎo)航守衛(wèi)(導(dǎo)航鉤子)

4.2.1 全局導(dǎo)航守衛(wèi)

main.js 中進(jìn)行全局導(dǎo)航守衛(wèi)注冊(cè)淹真。可以用 beforeEach 驗(yàn)證用戶是否登錄羽峰,如果未登錄趟咆,自動(dòng)跳轉(zhuǎn)至登錄頁(yè)面添瓷。next() 中參數(shù)配置同 route-link 中參數(shù)配置。

必須執(zhí)行 next()值纱,不然不會(huì)進(jìn)入鉤子鳞贷。

// main.js
import Vue from 'vue'
import VueRouter from 'vue-router'

import App from './App.vue'

import createRouter from './router/router'

Vue.config.productionTip = false

Vue.use(VueRouter)
const router = createRouter()

// 全局導(dǎo)航守衛(wèi)
router.beforeEach((to, from, next) => {
  console.log('main beforeEach invoked')
  if (to.fullPath !== '/login') { // 路由匹配到才回去執(zhí)行 next,如果不匹配,只打印 beforeEach invoked虐唠,而不會(huì)繼續(xù)打印beforeResolve invoked 和 afterEach invoked
    next('/login')
  }else {
    next () // 執(zhí)行 next 后路由才會(huì)被跳轉(zhuǎn)
  }
})
router.beforeResolve((to, from, next) => {
  console.log('main beforeResolve invoked')
  next()
})
router.afterEach((to, from) => { // 每次導(dǎo)航跳轉(zhuǎn)結(jié)束后被觸發(fā)搀愧,因?yàn)橐呀?jīng)跳轉(zhuǎn),所以不再需要 next
  console.log('main afterEach invoked')
})

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

頁(yè)面觸發(fā)順序(每次路由變化都會(huì)被觸發(fā)):

4-2-1-1.png

4.2.2 路由導(dǎo)航守衛(wèi)

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    props: {
      id: '456',
      sex: 'man'
    },
    components: {
        default: Login,
        myRouteView: Home
    },
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
    // 在路由配置時(shí)增加鉤子
    // 進(jìn)入這個(gè)路由前調(diào)用這個(gè)鉤子疆偿,調(diào)用順序在 beforeEach 和 beforeResolve 之間
    beforeEnter (to, from, next) {
      console.log('route beforeEnter')
      next()
    }
  },
  //...
]

頁(yè)面觸發(fā)順序:

4-2-2-1.png

4.2.3 組件導(dǎo)航守衛(wèi)

? beforeRouteEnter 時(shí)咱筛,組件尚未被創(chuàng)建(未實(shí)例化),故還無(wú)法取到 this杆故,無(wú)法調(diào)用 this 上任何內(nèi)容迅箩,也無(wú)法給 this 賦值。這時(shí)可使用組件對(duì)象 vm (即組件創(chuàng)建后 this 的對(duì)象)处铛。

? beforeRouteLeave 可用于讓用戶確認(rèn)是否離開(kāi)次路由饲趋。

<!-- beforeRouteLeave -->
<template>
  <div>
    <div>Login頁(yè)內(nèi)容</div>
    <router-view />
  </div>
</template>

<script>
  export default {
    props: ['id', 'sex'],
    mounted () {
      console.log(this.id, this.sex)
    },
    beforeRouteEnter (to, from, next) {
      console.log("component beforeRouteEnter")
      next(vm => {
        console.log(this) // 打印為 undefined
        console.log(vm.id)
      })
    },
    beforeRouteUpdate (to, from, next) {
      console.log("component beforeRouteUpdate")
      next()
    },
    beforeRouteLeave (to, from, next) {
      console.log("component beforeRouteLeave")
      next()
    }
  }
</script>

進(jìn)入頁(yè)面時(shí)觸發(fā)順序(beforeRouteEnter):

4-2-3-1.png

更新頁(yè)面時(shí)觸發(fā)順序(beforeRouteUpdate,例如 login/123 切換至 login/456撤蟆,Login 組件不會(huì)被銷(xiāo)毀后重建奕塑,而是內(nèi)容更新):

4-2-3-2.png

切換頁(yè)面時(shí)觸發(fā)順序(beforeRouteLeave):

4-2-3-3.png

提示:例如 login/123 切換至 login/456 是,由于 Login 組件復(fù)用家肯,不會(huì)再次去調(diào)用 mounted龄砰,此時(shí)可使用 beforeRouteUpdate

4.3 異步組件

路由在非常多的情況下讨衣,如果通過(guò) webpack 一次性打包所有代碼换棚,會(huì)導(dǎo)致 js 文件龐大,初次加載耗時(shí)值依,且訪問(wèn)某一頁(yè)面時(shí)也加載了其他頁(yè)面的 js 代碼圃泡,造成資源浪費(fèi)。如果對(duì)于某一路由愿险,只加載對(duì)應(yīng)頁(yè)面代碼及核心代碼颇蜡,其他頁(yè)面代碼待訪問(wèn)時(shí)再加載,可使用異步組件加載辆亏,提高首屏加載速度风秤。

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    props: {
      id: '456',
      sex: 'man'
    },
    components: {
        default: Login,
        myRouteView: Home
    },
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild') // 異步組件加載,routers.js 頂部不必再引入 loginChild 組件
      }
    ],
    beforeEnter (to, from, next) {
      console.log('route beforeEnter')
      next()
    }
  },
  //...
]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扮叨,一起剝皮案震驚了整個(gè)濱河市缤弦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌彻磁,老刑警劉巖碍沐,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狸捅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡累提,警方通過(guò)查閱死者的電腦和手機(jī)尘喝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)斋陪,“玉大人朽褪,你說(shuō)我怎么就攤上這事∥扌椋” “怎么了缔赠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)友题。 經(jīng)常有香客問(wèn)我嗤堰,道長(zhǎng),這世上最難降的妖魔是什么度宦? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任梁棠,我火速辦了婚禮,結(jié)果婚禮上斗埂,老公的妹妹穿的比我還像新娘。我一直安慰自己凫海,他們只是感情好呛凶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著行贪,像睡著了一般漾稀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上建瘫,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天崭捍,我揣著相機(jī)與錄音,去河邊找鬼啰脚。 笑死殷蛇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的橄浓。 我是一名探鬼主播粒梦,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼荸实!你這毒婦竟也來(lái)了匀们?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤准给,失蹤者是張志新(化名)和其女友劉穎泄朴,沒(méi)想到半個(gè)月后重抖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡祖灰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年钟沛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夫植。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡讹剔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出详民,到底是詐尸還是另有隱情延欠,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布沈跨,位于F島的核電站由捎,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏饿凛。R本人自食惡果不足惜狞玛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涧窒。 院中可真熱鬧心肪,春花似錦、人聲如沸纠吴。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)戴已。三九已至固该,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間糖儡,已是汗流浹背伐坏。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留握联,地道東北人桦沉。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拴疤,于是被迫代替她去往敵國(guó)和親永部。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容