- 前後端路由的來歷
- 前端如何實現頁面跳轉但是不重新整理?
瞭解hash和history兩種方法 - vue-router基本使用
-
安裝vue-router
-
搭建vue-router框架的步驟
-
vue-router路由的配置步驟
- 第一步: 建立路由元件
- 第二步: 配置路由對映。 即:元件和路由的關係
- 第三步: 使用路由, 通過<router-link>和<router-view>來展示元件
-
路由的預設配置
-
修改靜態路由的模式為history
-
vue-link屬性設定
-
通過程式碼跳轉路由
-
動態路由的使用
-
路由的懶載入
-
- vue-router的巢狀
- vue-router引數傳遞
- vue-router導航守衛
- keep-alive
說道路由, 我們最熟悉的路由是什麼呢? 那就是路由器了。 其實路由器有兩個重要的功能: 路由和傳送
-
路由: 路由決定資料包從哪裡來, 到哪裡去。 也有是來源和目的地的路徑。
路由中有一個路由表, 路由表本質上就是一個對映表,決定了資料包的傳輸方向。
-
傳送: 傳送是將輸入端的資料傳送給輸出端
下面我們先來搭建一個專案, 然後一邊學習一遍在專案裡實戰
建立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
這兩種模式都可以實現頁面跳轉,但是不重新整理頁面. 他們如何使用, 又有什麼區別呢?
1. hash
首先啟動vue專案
vue init dev
然後開啟頁面
localhost:8080
在瀏覽器控制檯輸入localhost.hash="about", 我們可以看到頁面連結變成了localhost:8080/#/about/
如上圖, 我們可以通過location.hash="連結"的方式來修改url,但是並不重新整理頁面
2. history
除了使用hash,我們還可以使用history來改變實現改變url但不重新整理頁面的方法. history有幾個常見的用法.
- history.pushState(state,"title","url")
向瀏覽器新增一條歷史記錄,但是不會重新整理當前頁面(不會過載)
- state為物件,可以用作攜帶資訊用,
- title:目前來看沒啥用一般為空或null,
- URL:即要更改頁面的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-router是Vue.js官方的路有外掛, 他和vue.js是深度整合的.適合構建於單頁面富應用.
vue-router官網: https://router.vuejs.org/zh/
- vue-router是基於路由和元件的: 路由用於設定訪問路徑, 將路徑和元件對映起來
- 在vue-router的單頁面應用中, 頁面的路徑的改變就是元件的切換.
1. 安裝vue-router
npm install vue-router --save
--save: 表示在構建以後也要使用這個路由
安裝好以後, 在package.json中就可以看到安裝的vue-router的版本了
並且在src目錄下多了一個資料夾router
2. 搭建vue-router框架的步驟
在我們安裝了vue-router以後,就會在src目錄下自動生成一個資料夾router.
我們在裡面建立一個index.js檔案, 然後開始配置路由相關的資訊
- 第一步: 匯入路由物件,並且呼叫vue.use(VueRouter)
安裝了vue-router, 要想使用, 還需要先引入路由物件
import Router from 'vue-router'
vue-router是一個外掛, 所以, 我們需要使用vue.use(外掛名) 來安裝外掛
Vue.use(Router)
- 第二步: 建立路由例項,並且傳入路由對映配置
在VueRouter中主要是配置路由和元件之間的對映關係的.
const routes = [
]
const router = new VueRouter({
// 這裡配置的是路由和元件的對映關係, 是一個陣列.
routes
})
在這裡路由是空的, 還沒有配置任何對映關係.
- 第三步: 將vue-router例項物件匯出
export default router
- 第四步: 在vue例項中掛載建立的路由例項
import router from './router'
在import目錄的時候, 有一個預設的規則, 那就是如果你匯入一個目錄, 比如./router, 沒指定匯入哪一個檔案, 他會自動匯入index.js檔案*
然後在vue例項中引入router
new Vue({
el: '#app',
// 然後通過router匯入vue路由
router,
render: h => h(App)
})
3. vue-router路由的配置步驟
- 第一步: 建立路由元件
通常, 我們會在components目錄下建立元件。滑鼠右擊-> Vue Component, 然後定義元件內容
我們建立兩個元件, 一個首頁, 一個關於頁面.
首頁
<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
}
]
- 第三步: 使用路由, 通過<router-link>和<router-view>來展示元件
現在元件有了, 路有關係也有了。 那麼接下來就是要有個入口來展示元件或者路由了。 我們的入口只有一個, 那就是App.vue, 所以, 我們直接在這裡定義兩個入口即可。
<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>: 會根據當前的路徑, 動態渲染元件的內容
網頁的其他內容, 例如:頂部的標題/導航,底部的版權資訊等和/
處於一個等級 在切換路由時, 切換的是掛在組建的內容, 其他不會發生改變
整體效果如下:
4. 路由的預設配置
現在我們進入首頁顯示的只有導航資訊, 在頁面必須點選某一個按鈕,才能渲染出對應元件的內容。通常我們會有一個預設元件的展示。 否則首頁內容就是空的了。如何設定預設展示的路由呢?
在路由表中增加一個重定向路由
{
path:"/",
redirect: "/home"
}
這樣, 開啟首頁,直接載入home元件的內容
5. 修改靜態路由的模式為history
我們之前都是採用hash的方式來靜態路由跳轉的, 但hash方式有一個缺點, 即帶有#
例如:我們跳轉都Home頁, 他的路徑是
http://localhost:8080/#/home
帶有一個#, 這不符合我們通常路徑的使用方法,所以,我們可以考慮將其替換為history的模式。 如何替換呢? 在router/index.js檔案中
const router = new Router({
// 這裡配置的是路由和元件的對映關係, 是一個陣列.
routes,
mode: "history"
})
6. vue-link屬性設定
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"
})
7. 通過程式碼跳轉路由
上面我們都是在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"): 不可以使用瀏覽器的前進和後退按鈕路由.
8. 動態路由的使用
動態路由是什麼概念呢? 通常我們的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>
9. 認識路由的懶載入
首先為什麼需要懶載入, 原因是, 當我們打包的時候, 會將所有的js檔案,css進行打包, 打包到一個檔案中, 然後在index.html頁面中引入這些js,css檔案.我們來看一下效果
首先, 我們先將專案打包, 然後看看打包後的檔案結構
npm run build
打包完成以後, 會生成一個dist的資料夾,裡面就是打包後的檔案
如上圖檔案結構如下:
有一個index.html檔案和static資料夾
- index.html: 專案的主頁面入口
- static資料夾: 存放的是css和js等靜態資源
- css資料夾: 裡面只有一個app.*.css檔案, 這個檔案是將所有的css整合到這裡了
- js資料夾: 該資料夾中有三個檔案
- app.*.js: 這個檔案整合的是我們自己寫的業務邏輯相關的js程式碼
- manifest.*.js: 這個檔案整合的是支撐我們的業務邏輯的底層支撐js程式碼
- vendor.*.js: 這個檔案整合了使用到的所有外部元件的js程式碼
一個專案可能有很多元件, 有自定義的元件, 有引入的外部元件, 那就會有很多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個檔案, 因為使用了三個懶載入元件.
二. vue-router的巢狀
巢狀路由是一個很常見的功能, 比如主業引入了元件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
}]
}
裡面的路徑依然是有兩個部分:
- 一個是path路由路徑: 這裡需要注意的是,不需要在路徑名的前面加/
- 另一個是component: 指定元件名稱
第三步: 增加<router-link> 和 <router-view/>
我們要在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引數傳遞
vue-router引數傳遞有兩種方式: 第一種是: param的方式. 第二種是: query的方式
1. param方式
這種方式在動態路由的時候有提到過. 下面來回顧一下:
第一步: 建立一個User.vue元件
<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
第三步: 在App.vue中定義動態路由跳轉的元件
<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元件
首先, 在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}}的寫法
以上是使用引數的方式傳遞變數.
2. query方式
第一步: 配置路由的時候是普通配置: /user
第二步:傳遞的方式使用query的方式, query是一個物件,
第三步:傳遞後形成的路徑是:/user?useId=2, /user?userId=9
下面來舉個案例:
第一步: 建立一個元件Profile.vue
<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
第五步: 在Profile元件中獲取引數
獲取引數有兩種方式
- 直接語法糖方式獲取{{$route.query.***}}
- 在指令碼中獲取:this.$route.query.***
如下采用方式一獲取引數:
<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>
第六步: 檢視效果
四. vue-router導航守衛
導航守衛, 聽者特別的高大上. 到底是什麼意思呢?
在之前的html頁面, 如果我們想要實現title跟著頁面變, 那麼只需要設定html頁面的title屬性就可以了.
在vue中, 只有一個index.html頁面,如何實現title的改變呢?
有兩種方法:
- 第一種, 使用生命週期函式created().
- 第二種: 使用全域性導航守衛
1. 使用生命週期實現頁面更新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()函式. 雖然可以實現功能,但似乎有些麻煩, 有沒有可以統一修改的辦法呢?我們可以使用全域性導航守衛實現
3.2. 使用全域性導航守衛的方式更新title屬性
什麼是導航守衛?
來看看官網的解釋: https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
正如其名,vue-router 提供的導航守衛主要用來通過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程中:全域性的, 單個路由獨享的, 或者元件級的。
- 這裡的導航,指的就是路由的跳轉或者取消跳轉
- 守衛指的是: 有很多鉤子方法, 允許我們在某一個過程中植入程式碼邏輯.
- 常見的導航守衛有: 全域性導航守衛(包括三個: 全域性前置守衛, 全域性解析守衛, 全域性後置守衛), 路由獨享導航守衛, 元件內的守衛.
下面老看看[全域性前置守衛]
1. 使用 router.beforeEach 註冊一個全域性前置守衛
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) =>{
})
兩種都是可以的.
接下來, 看看函式中三個引數都是什麼含義呢?
- to: 是一個router物件, 含義是導航到的目標路徑.
- from: 是一個router物件, 含義是當前導航正要離開的路由.
- next: 是一個函式, 這是一個鉤子函式. 一定要呼叫該方法來 resolve 這個鉤子
函式實現的部分, 一定要呼叫next()方法. 表示導航繼續向下執行. 如果不呼叫next(), 那麼後面的函式將不會被解析或者執行.
也就是說, 程式碼這至少是這樣的
router.beforeEach((to, from, next) =>{
next();
})
確保 next 函式在任何給定的導航守衛中都被嚴格呼叫一次。它可以出現多於一次,但是隻能在所有的邏輯路徑都不重疊的情況下,否則鉤子永遠都不會被解析或報錯。
2. 在路由index.js檔案中增加後設資料屬性, 並設定title屬性值
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: "檔案"
}
3. 後面在全域性導航路由中設定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
我們有首頁, 關於, 使用者, 檔案. 首頁下面有兩個按鈕[新聞],[訊息]
當點選首頁的[訊息], 然後切換到關於頁面, 再回到首頁的時候, 我們希望能夠繼續展示[訊息]的內容
預設是不會保留操作的記憶的. 下次回來直接到[首頁->新聞], 使用keep-alive就可以有保留記憶的效果了
為什麼每次回到首頁, 都會展示[首頁->新聞]的內容呢?
原因是每次回到首頁都會建立一個新的Home元件.
我們來驗證每次回到首頁都會重新建立一個新的元件. 來看看vue元件的生命週期. 其實Vue物件本身也是一個大元件
如上圖所示:在vue整個生命週期, 他有很多掛載函式, 比如:beforeCreate(建立元件之前), created(建立元件後), beforeMount(掛載元件之前), mounted(掛載元件之後),
beforeUpdate(元件值更新之前),updatd(元件值更新之後),beforeDestroy(元件銷燬之前),destroyed(元件銷燬之後)
1. 驗證, 是否銷燬了原來的元件呢?
我們只需要驗證created()和destroyed()兩個函式是否每次跳走都會被執行一遍.
<script>
export default {
name: "Home",
created() {
document.title="首頁"
console.log("created home")
},
destroyed() {
console.log("destroyed home")
}
}
</script>
如上所示:定義了建立函式和銷燬函式, 下面來看看當跳走的時候, 是不是會執行這兩個函式.
如上圖所示: 當離開首頁,就會執行destroyed函式, 當進入首頁, 就會執行created函式. 說明每次確實都在建立新的元件
2. 如何才能讓元件有記憶,而不是每次都重新建立呢?
如果想要實現路由跳轉走以後, 返回來不需要重新建立元件, 我們可以使用keep-alive, 他的用法很簡單
在組建展示的位置增加
<keep-alive>
<router-view></router-view>
</keep-alive>
這樣調走再跳回來就不會重新建立組建了, 來看看效果
我們看到只有第一次建立了home元件, 後來路由調走, 元件並沒有被銷燬.
3.案例: 實現從[首頁->banner圖]跳走後, 在跳回來, 依然定位在[首頁->banner圖]的位置
跳走, 在跳回來, 這實際上是在控制路由.我們可以讓路由調走之前記住當前元件的路由. 要想實現這個功能,需要了解一下幾個鉤子函式:
- 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, 在離開當前路由的時候, 記錄下離開前的路由.
程式碼實現如下:
1. 在home元件增加兩個方法, 一個是activated元件啟用的時候重定向路由, 另一個是beforeRouteLeave元件離開前記錄離開前的路由
activated() {
// 路由啟用, 路由到path路徑
this.$router.push(this.path)
},
beforeRouteLeave(to, from, next) {
console.log("離開home前的路徑 "+this.path)
this.path = this.$route.path;
next()
}
2. 看一下執行的效果:
以上就是keep-alive的內容, 這裡重要要有一個概念, 元件調走以後是會銷燬原來的元件的.如果我們不想它被銷燬, 那麼可以使用<keep-alive>元件實現.
4. keep-alive 的屬性
keep-alive有兩個屬性: 一個是include, 另一個是exclude
- include: 字串或者正規表示式, 只有匹配的元件才會被快取
- exclude: 字串或者正規表示式, 匹配到的元件不會被快取.
比如,我們整個元件都希望每次載入會快取, 但是檔案元件特殊, 希望他每次都被銷燬, 重新建立.
第一步: 在Profile元件中增加created和destroy事件
created() {
console.log("Profile created")
},
destroyed() {
console.log("Profile destroyed")
}
第二步: 在<keep-alive>中配置排除Profile元件
<keep-alive exclude="Profile">
<router-view></router-view>
</keep-alive>
這樣, Profile元件就不會被快取了