安裝vue-routerjavascript
搭建vue-router框架的步驟css
vue-router路由的配置步驟html
路由的默認配置前端
修改靜態路由的模式爲historyvue
vue-link屬性設置java
經過代碼跳轉路由android
動態路由的使用webpack
路由的懶加載ios
路由: 路由決定數據包從哪裏來, 到哪裏去。 也有是來源和目的地的路徑。git
路由中有一個路由表, 路由表本質上就是一個映射表,決定了數據包的傳輸方向。
傳送: 傳送是將輸入端的數據傳送給輸出端
下面咱們先來搭建一個項目, 而後一邊學習一遍在項目裏實戰
建立vue-cli2項目
vue init webpacek vueroute
而後一路向下就能夠了, 若是本地建立項目很慢, 能夠採用離線建立項目的方式, 具體步驟:
- 下載webpack離線模板: https://github.com/vuejs-templates/webpack
- 將下載的模板壓縮包解壓,修改文件名爲wepback並放入到/Users/本身電腦的用戶名/.vue-templates文件夾中.
- 執行建立項目的命令: vue init webpack
--offline
先後端路由, 目前經歷了三個階段, 哪三個階段呢?
先後端一體(後端路由)階段: 這個階段相似早起的jsp頁面, 和java頁面混合在一塊兒, jsp裏面有css, js, 還有java代碼, 先後端都是混合在一塊兒的.
缺點很明顯, 先後端分工不明確.
這種方式採用的是後端路由
基本流程: 請求一個controller接口 --> 經過接口找到頁面 --> 渲染頁面 --> 返回給瀏覽器
先後端分離階段: 前端經過ajax調用的形式, 調用後臺接口. 前端主要負責頁面渲染, 後端主要提供api接口.
優勢: 先後端分離. 各司其職, 分明明確. API可複用性強, fe, android, ios均可用
此時用戶請求的就是一個html頁面, 頁面須要哪一個url了, 直接經過ajax請求到頁面.
基本流程: 瀏覽器url請求 -> html頁面 -> ajax請求api接口 -> 後臺接口響應數據 -> html頁面渲染 -> 返回給瀏覽器
單頁面富應用階段: 簡稱SPA, 全稱是simple page application. 最主要的特色是在先後端分離的基礎上加了一層前端路由. 這個路由是有前端來維護的一套路由.
單頁面指的是:一個html文件 + 一個js文件 + 一個css文件.
但是就一個網站來講, 不可能只有一個頁面. 那麼是如何實現的呢?咱們來看下圖
前端只有一個頁面index.html, 而各個功能都是一個組件, 將全部組件都放到index.html頁面中, 而後根據用戶的請求定位到某一個組件. 這個是誰來定位的呢?就是前端路由來定位, 在vue中前端路由就是vue-router.
前端路由的核心是什麼呢? 改變url, 可是頁面不進行總體刷新.
前面說了, vue使用的是單頁面富應用, 也就是一個index.html就是整個項目, 而後在內部在跳轉連接的時候, 不會刷新頁面, 實現這種方式有兩種方法:hash和history
這兩種模式均可以實現頁面跳轉,可是不刷新頁面. 他們如何使用, 又有什麼區別呢?
首先啓動vue項目
vue init dev
而後打開頁面
localhost:8080
在瀏覽器控制檯輸入localhost.hash="about", 咱們能夠看到頁面連接變成了localhost:8080/#/about/
如上圖, 咱們能夠經過location.hash="連接"的方式來修改url,可是並不刷新頁面
除了使用hash,咱們還可使用history來改變實現改變url但不刷新頁面的方法. history有幾個常見的用法.
- history.pushState(state,"title","url")
向瀏覽器新增一條歷史記錄,可是不會刷新當前頁面(不會重載)
案例: 咱們在vue的瀏覽器界面改變http://localhost:8080爲http://localhost:8080/about
如上圖所示: 當咱們執行history.pushState({a:1},null,"about");的時候, 瀏覽器並無刷新頁面(Network沒有請求), 可是url連接確實發生了變化
- history.replaceState(state,title,URL)
更改當前瀏覽器的歷史記錄,即把當前執行此代碼頁面的記錄給替換掉,參數與第一條相同
- history.back()、history.forward()、history.go()
分別爲前進一個歷史,後退一個,history.go(Number),其中Number可正可負,即向前或向後若干個記錄
案例:
如上圖, 當咱們使用history.back()命令的時候, 會回退到上一個頁面, 也並無發生更新.
- history.state
返回當前頁面狀態參數,此參數通常由history.pushState(state,title,URL);以及history.replaceState(state,title,URL);附帶的state值,例子以下:
案例:
如上圖: 能夠看出history.state就是取出了pushState和replaceState兩個命令中的第一個參數
- history.length
返回當前頁面所產生的歷史記錄個數,即在同一個瀏覽器tab下產生的歷史記錄;
- history事件onpopstate
window.onpopstate = function(e){ console.log(e.state); }
在history.back(),history.forward(),history.go()時觸發此事件,可是在history.pushState();history.replaceState();時並不會觸發此事件,事件內能夠獲取到state狀態值
能夠看出vue-router中push()、go()等函數是基於hash和histroy的,可是vue-router比這個要複雜.
vue-router是Vue.js官方的路有插件, 他和vue.js是深度集成的.適合構建於單頁面富應用.
vue-router官網: https://router.vuejs.org/zh/
npm install vue-router --save
--save: 表示在構建之後也要使用這個路由
安裝好之後, 在package.json中就能夠看到安裝的vue-router的版本了
而且在src目錄下多了一個文件夾router
在咱們安裝了vue-router之後,就會在src目錄下自動生成一個文件夾router.
咱們在裏面建立一個index.js文件, 而後開始配置路由相關的信息
import Router from 'vue-router'
vue-router是一個插件, 因此, 咱們須要使用vue.use(插件名) 來安裝插件
Vue.use(Router)
const routes = [ ] const router = new VueRouter({ // 這裏配置的是路由和組件的映射關係, 是一個數組. routes })
在這裏路由是空的, 尚未配置任何映射關係.
export default router
import router from './router'
在import目錄的時候, 有一個默認的規則, 那就是若是你導入一個目錄, 好比./router, 沒指定導入哪個文件, 他會自動導入index.js文件*
而後在vue實例中引入router
new Vue({ el: '#app', // 而後經過router導入vue路由 router, render: h => h(App) })
首頁
<template> <div> <h2>這是Home主頁</h2> <div>歡迎來到home主頁</div> </div> </template> <script> export default { name: "Home" } </script> <style scoped> </style>
關於頁面
<template> <div> <h2>關於頁面</h2> <div>歡迎來到關於頁面</div> </div> </template> <script> export default { name: "About" } </script> <style scoped> </style>
這樣組件就建立好了。
組件建立好了, 接下來要構建組件和路由的關係。 構建路由關係,咱們一般定義在router/index.js文件
映射關係主要有兩個部分. 一個是path:路由的路徑; 一個是component:關聯的組件
在router/index.js文件中首先引入上面定義好的組件
import Home from '../components/Home'; import About from "../components/About";
而後指定路由路徑和組件
const routes = [ { path: "/home", component: Home },{ path: "/about", component: About } ]
<template> <div id="app"> <!-- 定義兩個路由連接 --> <router-link to="/home">首頁</router-link> <router-link to="/about">關於</router-link> <!-- 展現組件內容 --> <router-view></router-view> </div> </template>
<router-link>: 是一個vue-router中內置的組件, 它會被渲染成一個a標籤。
<router-vie>: 會根據當前的路徑, 動態渲染組件的內容
網頁的其餘內容, 例如:頂部的標題/導航,底部的版權信息等和/
處於一個等級 在切換路由時, 切換的是掛在組建的內容, 其餘不會發生改變
總體效果以下:
如今咱們進入首頁顯示的只有導航信息, 在頁面必須點擊某一個按鈕,才能渲染出對應組件的內容。一般咱們會有一個默認組件的展現。 不然首頁內容就是空的了。如何設置默認展現的路由呢?
在路由表中增長一個重定向路由
{ path:"/", redirect: "/home" }
這樣, 打開首頁,直接加載home組件的內容
咱們以前都是採用hash的方式來靜態路由跳轉的, 但hash方式有一個缺點, 即帶有#
例如:咱們跳轉都Home頁, 他的路徑是
http://localhost:8080/#/home
帶有一個#, 這不符合咱們一般路徑的使用方法,因此,咱們能夠考慮將其替換爲history的模式。 如何替換呢? 在router/index.js文件中
const router = new Router({ // 這裏配置的是路由和組件的映射關係, 是一個數組. routes, mode: "history" })
1. to屬性
咱們在首頁, 定義vue-link跳轉的路由使用的就是to屬性
<template> <div id="app"> <!-- 定義兩個路由連接 --> <router-link to="/home">首頁</router-link> <router-link to="/about">關於</router-link> <!-- 展現組件內容 --> <router-view></router-view> </div> </template>
2. tag屬性
<router-link> 默認會被渲染成a標籤, 若是咱們想要將其渲染爲其餘標籤是否能夠呢? 固然是能夠的, 使用tag屬性, 好比: 咱們想要將其渲染爲button標籤
<template> <div id="app"> <!-- 定義兩個路由連接 --> <router-link to="/home" tag="button">首頁</router-link> <router-link to="/about" tag="button">關於</router-link> <!-- 展現組件內容 --> <router-view></router-view> </div> </template>
3. replace屬性
以下圖, 咱們在點擊導航之後, 能夠在瀏覽器向前或向後導航
若是咱們不想要瀏覽器記錄咱們的請求行爲, 可使用replace. 咱們只須要在<router-link>標籤中增長屬性replace就能夠了. 這個屬性不須要設置值
<template> <div id="app"> <!-- 定義兩個路由連接 --> <router-link to="/home" tag="button" replace>首頁</router-link> <router-link to="/about" tag="button" replace>關於</router-link> <!-- 展現組件內容 --> <router-view></router-view> </div> </template>
效果以下: 瀏覽器的返回和前進按鈕都不可用
4. active-class 修改激活時樣式名稱的默認值
先來看看如何設置<router-link>元素的樣式.
在點擊按鈕的時候, 在控制檯能夠看到有一個樣式router-link-active, 這個樣式是控制按鈕激活的樣式, 若是咱們想要修改激活的效果, 修改這個樣式便可.
好比: 咱們設置按鈕激活時字體顏色爲紅色.
<template> <div id="app"> <!-- 定義兩個路由連接 --> <router-link to="/home" tag="button" replace>首頁</router-link> <router-link to="/about" tag="button" replace>關於</router-link> <!-- 展現組件內容 --> <router-view></router-view> </div> </template> <script> export default { name: 'App' } </script> <style> .router-link-active { color:red; } </style>
重點看style裏面的樣式定義. 效果以下:
router-link-active是vue-router默認/
<template> <div id="app"> <!-- 定義兩個路由連接 --> <router-link to="/home" tag="button" replace active-class="active">首頁</router-link> <router-link to="/about" tag="button" replace active-class="active">關於</router-link> <!-- 展現組件內容 --> <router-view></router-view> </div> </template>
如上, 能夠看到active-class="active", 表示將默認的屬性重命名爲active.
後面重定義樣式的時候, 使用active便可
<style> .active { color:red; } </style>
全局修改active-clas的默認名稱. 能夠在路由裏實現.
修改router/index.js文件
const router = new Router({ // 這裏配置的是路由和組件的映射關係, 是一個數組. routes, mode: "history", linkActiveClass: "active" })
上面咱們都是在vue中直接使用<router-link>來路由, 咱們還可使用普通標籤路由, 例如button標籤, 來看看怎麼實現
第一步: 定義兩個button元素
<template> <div id="app"> <!-- 定義兩個路由連接 --> <button @click="clickHome">首頁</button> <button @click="clickAbout">關於</button> <!-- 展現組件內容 --> <router-view></router-view> </div> </template>
這就是兩個普通的button, 而後定義了兩個click點擊事件, 下面咱們就要在點擊事件中實現路由
第二步: 定義click事件, 路由到組件
<script> export default { name: 'App', methods:{ clickHome() { this.$router.push("/home") console.log("點擊home按鈕") }, clickAbout() { this.$router.push("/about") console.log("點擊about按鈕") } } } </script>
這裏定義了點擊事件. 經過this.$router.push("/home")來路由到home組件.
this.$router.push("/home"): 在每個vue對象中, 經過this均可找到$router屬性, 這是一個全局的屬性.
this.$router.push("/home")是使用history的的方式路由到對應的組件, 能夠經過瀏覽器的前進和後退按鈕路由.
this.$router.replace("/home"): 不可使用瀏覽器的前進和後退按鈕路由.
動態路由是什麼概念呢? 一般咱們的url是不變的, 好比. /home, 有些url是變化的,好比/user/zhangsan, /user/lisi, 對於變化的url, 咱們如何路由呢?
下面就以用戶爲例, 來實現動態路由
第一步: 建立一個User.vue模板
<template> <div> <h2>用戶界面</h2> <div>歡迎你來到用戶界面</div> </div> </template> <script> export default { name: "User" } </script> <style scoped> </style>
第二步: 添加路由映射關係
import User from "../components/User" const routes = [ { path: "/user/:userId", component: User } ]
這裏path使用了:userId佔位, 表示這裏是一個佔位符, 將被真實的userId替換. 後面在路由傳遞的時候變量須要和這裏保持一致.
第三步: 使用user路由
當咱們動態路由到user的時候, 須要使用變量userId, 咱們能夠在data中定義一個變量
<template> <div id="app"> <!-- 定義兩個路由連接 --> <router-link to="/home" tag="button" replace active-class="active">首頁</router-link> <router-link to="/about" tag="button" replace active-class="active">關於</router-link> <router-link v-bind:to="'/user/'+userId" tag="button" replace active-class="active">用戶</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'App', data(){ return { userId:"zhangsan" } } } </script>
在上面使用了v-bind:to="'/user/'+userId"路由到/user/:userId, 而userId是咱們在組件中定義的一個變量.
第三步:來看看效果
咱們看到當點擊用戶的時候, 瀏覽器的url路徑變爲了/user/zhangsan.
第四步: 將參數傳遞到組件
咱們但願在user組件中顯示, 歡迎{{用戶名}}來到用戶頁面, 如何實現呢?
要想實現這個效果, 須要使用到this.$route對象. 這是獲取路由信息的對象.
<template> <div> <h2>用戶界面</h2> <div>歡迎{{userId}},來到用戶界面</div> </div> </template> <script> export default { name: "User", data(){ return { userId:this.$route.params.userId } } } </script> <style scoped> </style>
能夠看到在data屬性中,咱們經過this.$route.params.userId 獲取到了路由鏈接中的userId參數.
而後在頁面經過語法糖的方式展現出用戶{{userId}}便可.
來看看效果:
如上圖所示, 咱們看到userId變量被傳遞到了組件裏面.
這裏重點想要說的就是經過this.$route.params獲取變量.
咱們也能夠在頁面直接使用{{$route.params.userId}}獲取路由參數
<template> <div> <h2>用戶界面</h2> <div>歡迎{{userId}},來到用戶界面</div> <div>{{$route.params.userId}}</div> </div> </template>
首先爲何須要懶加載, 緣由是, 當咱們打包的時候, 會將全部的js文件,css進行打包, 打包到一個文件中, 而後在index.html頁面中引入這些js,css文件.咱們來看一下效果
首先, 咱們先將項目打包, 而後看看打包後的文件結構
npm run build
打包完成之後, 會生成一個dist的文件夾,裏面就是打包後的文件
如上圖文件結構以下:
有一個index.html文件和static文件夾
一個項目可能有不少組件, 有自定義的組件, 有引入的外部組件, 那就會有不少js, css代碼, 最終所有經過index.html加載進來, 這樣在首次加載的時候速度就會很慢. 因此, 咱們須要使用懶加載, 來提升首次加載速度.
什麼是懶加載呢?
使用時才加載, 就是懶加載, 而不是一次性所有加載進來
怎樣才能作到懶加載呢?
把不一樣的路由對應的組件分隔成不一樣的代碼塊, 而不是統一所有加載到app.*.js文件中,當路由被訪問的時候才加載對應的js文件, 這樣會更加高效
如何實現懶加載呢?
在路由定義的時候, 是有懶加載的方式
原來定義路由是這樣的
import Home from '../components/Home'; import About from "../components/About"; import User from "../components/User" /* * 第一步: 安裝插件 * vue-router是一個插件, 因此, 咱們須要使用vue.use(插件名) 來安裝插件 */ Vue.use(Router) /* * 第二步: 構建VueRouter對象 * 在VueRouter中主要是配置路由和組件之間的映射關係的. */ const routes = [ { path:"/", redirect: "/home" }, { path: "/home", component: Home },{ path: "/about", component: About },{ path: "/user/:userId", component: User } ]
懶加載須要使用一個匿名函數來import, 表示使用的時候在import引入. 一個懶加載在打包的時候會單獨打包成一個js文件.
// 這裏會引入你要導入的組件, 而後經過路由配置組件內容 const Home = () =>import('../components/Home'); const About = () => import('../components/About'); const User = () => import('../components/User'); /* * 第一步: 安裝插件 * vue-router是一個插件, 因此, 咱們須要使用vue.use(插件名) 來安裝插件 */ Vue.use(Router) /* * 第二步: 構建VueRouter對象 * 在VueRouter中主要是配置路由和組件之間的映射關係的. */ const routes = [ { path:"/", redirect: "/home" }, { path: "/home", component: Home },{ path: "/about", component: About },{ path: "/user/:userId", component: User } ]
咱們將代碼的引入方式改變了,這樣在打包的時候, 會將每個import進來的文件打包成一個單獨的js文件. 以下圖所示:
和以前相比, 多了3個文件, 由於使用了三個懶加載組件.
嵌套路由是一個很常見的功能, 好比主業引入了組件Home, 咱們在Home裏面引入了banner圖組件. 這樣就是組件的嵌套.
咱們的路由映射規則是: 一個路徑映射一個組件. 訪問兩個路徑, 會分別渲染兩個組件.
下面來實現嵌套路由,
HomeBanner.vue組件
<template> <div> <h2>首頁banner圖</h2> <ul> <li>banner圖1</li> <li>banner圖2</li> <li>banner圖3</li> <li>banner圖4</li> </ul> </div> </template> <script> export default { name: "HomeBanner" } </script> <style scoped> </style>
HomeNews.vue組件
<template> <div> <h2>首頁新聞</h2> <ul> <li>第一條新聞</li> <li>第二條新聞</li> <li>第三條新聞</li> <li>第四條新聞</li> </ul> </div> </template> <script> export default { name: "HomeNews" } </script> <style scoped> </style>
咱們要在Home也添加子路由, 須要在路由裏面增長一個children屬性配置.
//引入子路由-使用懶加載的方式進行加載 const HomeBanner = ()=>import('../components/HomeBanner'); const HomeNews = () => import('../components/HomeNews'); { path: "/home", component: Home, children: [{ path:'', redirect: 'HomeNew' },{ path: 'HomeNew', //注意: 這裏面沒有/ component: HomeNews },{ path: 'HomeBanner', component: HomeBanner }] }
裏面的路徑依然是有兩個部分:
咱們要在Home頁面展現子組件, 所以須要將子組件的展現放在頁面上
<template> <div> <h2>這是Home主頁</h2> <div>歡迎來到home主頁</div> <router-link to="/home/homeNew">新聞</router-link> <router-link to="/home/homeBanner">Banner圖</router-link> <router-view></router-view> </div> </template>
完成之後,效果以下:
vue-router參數傳遞有兩種方式: 第一種是: param的方式. 第二種是: query的方式
這種方式在動態路由的時候有提到過. 下面來回顧一下:
<template> <div> <h2>用戶界面</h2> </div> </template> <script> export default { name: "User", } </script> <style scoped> </style>
const routes = [ { path: "/user/:userId", component: User } ]
咱們定義了一個user/:userId, 這樣的動態路由. 路由能夠是/user/zhangsan, 或者/user/lisi
<template> <div id="app"> <!-- 定義兩個路由連接 --> <router-link to="/home" tag="button" replace active-class="active">首頁</router-link> <router-link to="/about" tag="button" replace active-class="active">關於</router-link> <!-- 定義動態路由 --> <router-link v-bind:to="'/user/' + userId" tag="button" replace active-class="active">用戶</router-link> <!-- 展現組件內容 --> <router-view></router-view> </div> </template> <script> export default { name: 'App', data(){ return { userId:"zhangsan" } } } </script> <style> .active { color:red; } </style>
這裏面userId是變化的部分. 經過bind事件動態將userId綁定到path路徑中
<router-link v-bind:to="'/user/' + userId" tag="button" replace active-class="active">用戶</router-link>
首先, 在User.vue腳本中獲取傳遞過來的路由參數. 咱們使用[this.$route.params.變量名]的方式獲取路徑參數
<script> export default { name: "User", data() { return { userId: this.$route.params.userId } } } </script>
而後使用語法糖, 將變量顯示出來
<template> <div> <h2>用戶界面</h2> <div>歡迎{{userId}},來到用戶界面</div> <div>{{$route.params.userId}}</div> </div> </template>
也能夠直接使用使用{{$route.params.userId}}的寫法
以上是使用參數的方式傳遞變量.
第一步: 配置路由的時候是普通配置: /user
第二步:傳遞的方式使用query的方式, query是一個對象,
第三步:傳遞後造成的路徑是:/user?useId=2, /user?userId=9
下面來舉個案例:
<template> <div> <h2>這是一個Profile組件</h2> </div> </template> <script> export default { name: "Profile" } </script> <style scoped> </style>
// 配置路由相關的信息 // 導入vue和vue-router import Vue from 'vue' import Router from "vue-router"; // 這裏會引入你要導入的組件, 而後經過路由配置組件內容 // 懶加載 const Profile = () => import('../components/Profile') /* * 第一步: 安裝插件 * vue-router是一個插件, 因此, 咱們須要使用vue.use(插件名) 來安裝插件 */ Vue.use(Router) /* * 第二步: 構建VueRouter對象 * 在VueRouter中主要是配置路由和組件之間的映射關係的. */ const routes = [ { path: "/profile", component: Profile } ] const router = new Router({ // 這裏配置的是路由和組件的映射關係, 是一個數組. routes, mode: "history", linkActiveClass: "active" }) /* * 第三步: 將VueRouter對象導出 * */ export default router
<!-- 配置動態路由 --> <router-link v-bind:to="{path:'/profile', query:{name:'lily',sex:'男',age:12}}" tag="button" replace active-class="active">檔案</router-link>
一般咱們定義路由是這樣定義的
<!-- 配置動態路由 --> <router-link to="/profile" tag="button" replace active-class="active">檔案</router-link>
可是, 這樣路由就固定寫死了, 因此確定不行, 咱們須要給他一個變量, 使用v-bind:to
而後就有了下面這個寫法
v-bind:to="{path:'/profile', query:{name:'lily',sex:'男',age:12}}"
咱們看到路徑上帶了?參數.
http://localhost:8080/profile?name=lily&sex=%E7%94%B7&age=12
獲取參數有兩種方式
以下采用方式一獲取參數:
<template> <div> <h2>這是一個Profile組件</h2> <h4>{{$route.query}}</h4> <h4>{{$route.query.name}}</h4> <h4>{{$route.query.age}}</h4> <h4>{{$route.query.sex}}</h4> </div> </template>
導航守衛, 聽者特別的高大上. 究竟是什麼意思呢?
在以前的html頁面, 若是咱們想要實現title跟着頁面變, 那麼只須要設置html頁面的title屬性就能夠了.
在vue中, 只有一個index.html頁面,如何實現title的改變呢?
有兩種方法:
組件的生命週期, 這在以前有提到過. 子組件的生命週期中有不少函數, 好比created(), mouted(), updated(), 咱們能夠在他的生命週期增長處理邏輯.
,咱們能夠在created()方法中增長處理邏輯.
<template> <div> <h2>這是Home主頁</h2> <div>歡迎來到home主頁</div> <router-link to="/home/homeNew">新聞</router-link> <router-link to="/home/homeBanner">Banner圖</router-link> <router-view></router-view> </div> </template> <script> export default { name: "Home", created() { document.title="首頁" } } </script> <style scoped> </style>
咱們看到在script中增長一個created方法. 並指定了title名稱.
<script> export default { name: "Home", created() { document.title="首頁" } } </script>
來看一下效果
這樣有什麼問題? 假如如今有100個頁面, 咱們須要在100個頁面中都增長created()函數. 雖然能夠實現功能,但彷佛有些麻煩, 有沒有能夠統一修改的辦法呢?咱們可使用全局導航守衛實現
什麼是導航守衛?
來看看官網的解釋: https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
正如其名,vue-router 提供的導航守衛主要用來經過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程當中:全局的, 單個路由獨享的, 或者組件級的。
下面老看看[全局前置守衛]
const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... })
當一個導航觸發時,全局前置守衛按照建立順序調用。
守衛是異步解析執行,此時導航在全部守衛 resolve 完以前一直處於 等待中。
咱們來看看router.beforeEach的實現.
點擊beforeEach進入到router.ts文件, 能夠看到裏面定義了router.beforeEach()方法的定義
beforeEach(guard: NavigationGuard): Function
這是一個函數, 方法有一個入參, 參數是一個方法, 參數名是guard. 方法體是NavigationGuard. 咱們來看看NavigationGuard的實現邏輯
export type NavigationGuard<V extends Vue = Vue> = ( to: Route, from: Route, next: NavigationGuardNext<V> ) => any
NavigationGuard也是一個函數, 而且這個函數繼承自Vue. 函數有三個入參: to, from, next. 方法實現是any.
因此,咱們要想重寫beforeEach()方法. 那麼參數就要定一個方法, 而且方法裏有三個入參. 方法以下:
router.beforeEach(function(to, from, next) { })
除了這種方法, 咱們還可使用箭頭函數
router.beforeEach((to, from, next) =>{ })
兩種都是能夠的.
接下來, 看看函數中三個參數都是什麼含義呢?
函數實現的部分, 必定要調用next()方法. 表示導航繼續向下執行. 若是不調用next(), 那麼後面的函數將不會被解析或者執行.
也就是說, 代碼這至少是這樣的
router.beforeEach((to, from, next) =>{ next(); })
確保 next 函數在任何給定的導航守衛中都被嚴格調用一次。它能夠出現多於一次,可是隻能在全部的邏輯路徑都不重疊的狀況下,不然鉤子永遠都不會被解析或報錯。
const routes = [ { path:"/", redirect: "/home", }, { path: "/home", component: Home, children: [{ path:'', redirect: 'HomeNew' },{ path: 'homeNew', //注意: 這裏面沒有/ component: HomeNews },{ path: 'homeBanner', component: HomeBanner }], meta: { title: "首頁" } },{ path: "/about", component: About, meta: { title: "關於" } },{ path: "/user/:userId", component: User, meta: { title: "用戶" } },{ path: "/profile", component: Profile, meta: { title: "檔案" } } ]
增長的元數據內容以下
meta: { title: "檔案" }
router.beforeEach((to, from, next) => { console.log(to) console.log(from) document.title = to.matched[0].meta.title next() })
咱們經過打印to和from對象, 發現他們確實都是路由對象, 咱們能夠經過matched中的第0個元素,獲取到meta中的內容.
咱們看到其實to下面和matched平級的也有一個meta屬性, 可是這個屬性在某些狀況下值是空的. 因此, 咱們還經過matched的第一個元素來獲取meta對象
以上就是全局前置導航守衛的用戶, 後置導航守衛等其餘守衛, 用法與其類似, 能夠查看官方文檔: https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
前置守衛也好, 後置守衛也好, 都是路由組件的鉤子函數, 經過鉤子函數, 咱們能夠在對應的生命週期織入業務邏輯.
理解守衛的含義
全局前置守衛, 全局解析守衛, 全局後置守衛: 定義在路由文件中, 表示對全部路由都有效
路由獨享守衛: 能夠在路由配置上直接定義 beforeEnter 守衛:
組件內的守衛:你能夠在路由組件內直接定義如下路由導航守衛, 有效範圍是某個組件.
常見的組件內守衛: beforeRouteEnter(進入路由前),beforeRouteUpdate (更新路由前)),beforeRouteLeave(離開路有前)
咱們有首頁, 關於, 用戶, 檔案. 首頁下面有兩個按鈕[新聞],[消息]
當點擊首頁的[消息], 而後切換到關於頁面, 再回到首頁的時候, 咱們但願可以繼續展現[消息]的內容
默認是不會保留操做的記憶的. 下次回來直接到[首頁->新聞], 使用keep-alive就能夠有保留記憶的效果了
爲何每次回到首頁, 都會展現[首頁->新聞]的內容呢?
緣由是每次回到首頁都會建立一個新的Home組件.
咱們來驗證每次回到首頁都會從新建立一個新的組件. 來看看vue組件的生命週期. 其實Vue對象自己也是一個大組件
如上圖所示:在vue整個生命週期, 他有不少掛載函數, 好比:beforeCreate(建立組件以前), created(建立組件後), beforeMount(掛載組件以前), mounted(掛載組件以後),
beforeUpdate(組件值更新以前),updatd(組件值更新以後),beforeDestroy(組件銷燬以前),destroyed(組件銷燬以後)
咱們只須要驗證created()和destroyed()兩個函數是否每次跳走都會被執行一遍.
<script> export default { name: "Home", created() { document.title="首頁" console.log("created home") }, destroyed() { console.log("destroyed home") } } </script>
如上所示:定義了建立函數和銷燬函數, 下面來看看當跳走的時候, 是否是會執行這兩個函數.
如上圖所示: 當離開首頁,就會執行destroyed函數, 當進入首頁, 就會執行created函數. 說明每次確實都在建立新的組件
若是想要實現路由跳轉走之後, 返回來不須要從新建立組件, 咱們可使用keep-alive, 他的用法很簡單
在組建展現的位置增長
<keep-alive> <router-view></router-view> </keep-alive>
這樣調走再跳回來就不會從新建立組建了, 來看看效果
咱們看到只有第一次建立了home組件, 後來路由調走, 組件並無被銷燬.
跳走, 在跳回來, 這其實是在控制路由.咱們可讓路由調走以前記住當前組件的路由. 要想實現這個功能,須要瞭解一下幾個鉤子函數:
- activated: 路由激活時觸發
- deactivated: 路由取消激活時觸發
先來看這兩個: 這兩個函數生效的條件是 : 設置了<keep-alive>組件纔有效. 也就是說, 組件離開時不銷燬.
咱們在home組件中增長兩個方法
activated() { // 路由激活 console.log("activated home") }, deactivated() { // 路由取消激活 console.log("deactivated home") },
而後來看看效果: 咱們發現跳到home路由, 觸發activated方法, 離開home路由, 觸發deactivated方法.
如何記住路由呢? 咱們能夠定義一個變量來記住調走前的路由.
this.$route.path : 他是獲取當前激活的路由
要想實現這個功能, 還須要使用到路由守衛.
路由守衛有三種類型
const Foo = { template: `...`, beforeRouteEnter(to, from, next) { // 在渲染該組件的對應路由被 confirm 前調用 // 不!能!獲取組件實例 `this` // 由於當守衛執行前,組件實例還沒被建立 }, beforeRouteUpdate(to, from, next) { // 在當前路由改變,可是該組件被複用時調用 // 舉例來講,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候, // 因爲會渲染一樣的 Foo 組件,所以組件實例會被複用。而這個鉤子就會在這個狀況下被調用。 // 能夠訪問組件實例 `this` }, beforeRouteLeave(to, from, next) { // 導航離開該組件的對應路由時調用 // 能夠訪問組件實例 `this` } }
咱們選擇使用最後一個beforeRouteLeave, 在離開當前路由的時候, 記錄下離開前的路由.
代碼實現以下:
activated() { // 路由激活, 路由到path路徑 this.$router.push(this.path) }, beforeRouteLeave(to, from, next) { console.log("離開home前的路徑 "+this.path) this.path = this.$route.path; next() }
以上就是keep-alive的內容, 這裏重要要有一個概念, 組件調走之後是會銷燬原來的組件的.若是咱們不想它被銷燬, 那麼可使用<keep-alive>組件實現.
keep-alive有兩個屬性: 一個是include, 另外一個是exclude
好比,咱們整個組件都但願每次加載會緩存, 可是檔案組件特殊, 但願他每次都被銷燬, 從新建立.
created() { console.log("Profile created") }, destroyed() { console.log("Profile destroyed") }
<keep-alive exclude="Profile"> <router-view></router-view> </keep-alive>
這樣, Profile組件就不會被緩存了