1 路由的基本概念與原理
1.1路由:
前端路由
后端路由
- 介紹
- 路由的本質就是一種對應關系,比如說我們在url地址中輸入我們要訪問的url地址之后,瀏覽器要去請求這個url地址對應的資源。
- 那么url地址和真實的資源之間就有一種對應的關系,就是路由。
- 路由分為前端路由和后端路由
1). 后端路由是由服務器端進行實現,并完成資源的分發 (url與資源/數據的對應關系)
2). 前端路由是依靠hash值(錨點鏈接)的變化進行實現 (錨點與組件之間的關系)- 后端路由性能相對前端路由來說較低,所以,我們接下來主要學習的是前端路由
- 前端路由的基本概念:根據不同的事件來顯示不同的頁面內容,即事件與事件處理函數之間的對應關系
- 前端路由主要做的事情就是監聽事件并分發執行事件處理函數
1.2后端路由
介紹:
image.png
1.3SPA
總結:
image.png
- 后端渲染界面,只要有一處修改,就需要刷新整個界面,存在性能問題
- Ajax可以局部刷新,但是不支持前進后退
- spa可以局部刷新,也支持前進后退
1.4 前端路由
image.png
1.5 路由總結
- 路由:表示一種對應關系,某些事物的一 一對應的關系
- 后端路由:url與后端資源的一 一對應的關系
- 前端路由:用戶事件與事件處理函數一 一對應的關系
1.6 實現簡易前端路由
- 介紹
- 前端路由是基于hash值的變化進行實現的
- 這里的hash值指的是url的hash值,也就是界面的錨點
- 比如點擊頁面中的菜單或者按鈕改變URL的hash值,根據hash值的變化來控制組件的切換
- 核心實現依靠一個事件,即監聽hash值變化的事件
- 前端路由是基于hash值的變化進行實現的
window.onhashchange = function(){
//location.hash可以獲取到最新的hash值
location.hash
}
案例:
核心思路:
- 在頁面中有一個vue實例對象,vue實例對象中有四個組件,分別是tab欄切換需要顯示的組件內容
- 在頁面中有四個超鏈接,如下:
- 當我們點擊這些超鏈接的時候,就會改變url地址中的hash值,當hash值被改變時,就會觸發onhashchange事件
- 在觸發onhashchange事件的時候,我們根據hash值來讓不同的組件進行顯示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<!-- 導入 vue 文件 -->
<script src="./lib/vue_2.5.22.js"></script>
</head>
<body>
<!-- 被 vue 實例控制的 div 區域 -->
<div id="app">
<!-- 切換組件的超鏈接 -->
<a href="#/zhuye">主頁</a>
<a href="#/keji">科技</a>
<a href="#/caijing">財經</a>
<a href="#/yule">娛樂</a>
<!-- 根據 :is 屬性指定的組件名稱,把對應的組件渲染到 component 標簽所在的位置 -->
<!-- 可以把 component 標簽當做是【組件的占位符】 -->
<component :is="comName"></component>
</div>
<script>
// #region 定義需要被切換的 4 個組件
// 主頁組件
const zhuye = {
template: '<h1>主頁信息</h1>'
}
// 科技組件
const keji = {
template: '<h1>科技信息</h1>'
}
// 財經組件
const caijing = {
template: '<h1>財經信息</h1>'
}
// 娛樂組件
const yule = {
template: '<h1>娛樂信息</h1>'
}
// #endregion
// #region vue 實例對象
const vm = new Vue({
el: '#app',
data: {
comName: 'zhuye'
},
// 注冊私有組件
components: {
zhuye,
keji,
caijing,
yule
}
})
// #endregion
// 監聽 window 的 onhashchange 事件,根據獲取到的最新的 hash 值,切換要顯示的組件的名稱
window.onhashchange = function() {
// 通過 location.hash 獲取到最新的 hash 值
console.log(location.hash);
switch(location.hash.slice(1)){
case '/zhuye':
vm.comName = 'zhuye'
break
case '/keji':
vm.comName = 'keji'
break
case '/caijing':
vm.comName = 'caijing'
break
case '/yule':
vm.comName = 'yule'
break
}
}
</script>
</body>
</html>
2 vue-router的基本使用
2.1 基本使用
介紹
它是一個Vue.js官方提供的路由管理器。是一個功能更加強大的前端路由器,推薦使用
Vue Router和Vue.js非常契合,可以一起方便的實現SPA(single page web application,單頁應用程序)應用程序的開發
Vue Router依賴于Vue,所以需要先引入Vue,再引入Vue Router
官網:https://router.vuejs.org/zh/
Vue Router的特性:
- 支持H5歷史模式或者hash模式
- 支持嵌套路由
- 支持路由參數
- 支持編程式路由
- 支持命名路由
- ....
基本使用步驟:
1.導入js文件
2.添加路由鏈接
3.添加路由占位符(最后路由展示的組件就會在占位符的位置顯示)
4.定義路由組件
5.配置路由規則并創建路由實例
6.將路由掛載到Vue實例中
1.導入js文件
image.png
2.添加路由鏈接
image.png
3.添加路由占位符(最后路由展示的組件就會在占位符的位置顯示)
image.png
router-view:路由-視圖,顯示用戶點擊的路由鏈接對應的組件
- 視圖:組件可以顯示出具體內容,可以理解為視圖
- 例如:用戶點擊User路由鏈接,就會將User組件顯示到這里
4.定義路由組件
image.png
5.創建路由實例,并配置路由規則
image.png
6.將路由掛載到Vue實例中
image.png
- router是:router:router的簡寫
- 如果VueRouter的實例名是xxx,那掛載時,就需要寫:router:xxx
- Vue實例化時,參數el,data,methods,router都是固定的
代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<!--1. 導入 vue 文件 -->
<script src="./lib/vue_2.5.22.js"></script>
<script src="./lib/vue-router_3.0.2.js"></script>
</head>
<body>
<!--2. 添加路由鏈接:to渲染成href。to的值渲染成#hash值(錨點)-->
<!-- 被 vm 實例所控制的區域 -->
<div id="app">
<router-link to="/user">User</router-link><!--<a href="#/user"> User</a>-->
<router-link to="/register">Register</router-link>
<!-- 3.路由占位符 -->
<router-view></router-view>
</div>
<script>
//4.定義路由組件
const User = {
template: '<h1>User 組件</h1>'
}
const Register = {
template: '<h1>Register 組件</h1>'
}
//5. 配置路由規則,并創建路由實例
// 創建路由實例對象
const router = new VueRouter({
// 所有的路由規則
routes: [
{ path: '/user', component: User },
{ path: '/register', component: Register }
]
})
// 創建 vm 實例對象
const vm = new Vue({
// 指定控制的區域
el: '#app',
data: {},
//6.掛載路由實例對象
// router: router
router
})
</script>
</body>
</html>
2.2 路由重定向
介紹:
image.png
- rediret:重定向
- 普通的路由是定義path和component,訪問url顯示對應組件
- 重定向路由是定義path和redirect,訪問url跳轉到另一個url
代碼:
//將上一個案例的路由規則增加一個重定向:
// 創建路由實例對象
const router = new VueRouter({
// 所有的路由規則
routes: [
{ path: '/', redirect: '/user'},//增加這一行代碼,如果訪問跟路徑/,則重定向到/user
{ path: '/user', component: User },
{ path: '/register', component: Register }
]
})
效果:
- 再訪問:03.路由重定向.html
- 會跳轉:03.路由重定向.html#/user
3 vue-router嵌套路由
- 通過路由嵌套,可以處理復雜的界面
- 嵌套路由功能分析:如下圖:點擊Register之后發現Register組件中嵌套了另一塊內容
步驟:
1. 父路由組件模板
image.png
2 子級路由模板
image.png
- 因為子級模板是哎register組件內顯示的,所以應該定義在register組件的template中
- 在template添加路由連接,子url是/register開頭
- 在template添加router-view,給子組件占位
3 路由嵌套配置
image.png
- 作為register的子組件,那么就需要在register的children屬性中定義路由規則
代碼:
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<!-- 導入 vue 文件 -->
<script src="./lib/vue_2.5.22.js"></script>
<script src="./lib/vue-router_3.0.2.js"></script>
</head>
<body>
<!-- 被 vm 實例所控制的區域 -->
<div id="app">
<router-link to="/user">User</router-link>
<router-link to="/register">Register</router-link>
<!-- 路由占位符 -->
<router-view></router-view>
</div>
<script>
const User = {
template: '<h1>User 組件</h1>'
}
const Register = {
template: `<div>
<h1>Register 組件</h1>
<hr/>
<!-- 子路由鏈接 -->
<router-link to="/register/tab1">tab1</router-link>
<router-link to="/register/tab2">tab2</router-link>
<!-- 子路由的占位符 -->
<router-view />
<div>`
}
const Tab1 = {
template: '<h3>tab1 子組件</h3>'
}
const Tab2 = {
template: '<h3>tab2 子組件</h3>'
}
// 創建路由實例對象
const router = new VueRouter({
// 所有的路由規則
routes: [
{ path: '/', redirect: '/user'},
{ path: '/user', component: User },
// children 數組表示子路由規則
{ path: '/register', component: Register, children: [
{ path: '/register/tab1', component: Tab1 },
{ path: '/register/tab2', component: Tab2 }
] }
]
})
// 創建 vm 實例對象
const vm = new Vue({
// 指定控制的區域
el: '#app',
data: {},
// 掛載路由實例對象
// router: router
router
})
</script>
</body>
總結:
- 關于router-view和router-link的書寫位置:
- 路由規則在哪定義的,router-view和router-link就寫在誰的模板中
- Register和User定義在vm中,那么他們的router-view和router-link就定義在app中
- app這個div就可以理解為vm的模板
- Register和User可以理解為vm的子組件
- Tab1和Tab2定義在Register中,那么他們的router-view和router-link就定義Register中的模板中
- 路由規則在哪定義的,決定了自己的父組件是誰,那么子組件的router-view和router-link就定義在父組件的模板中
分析圖:
image.png
4 vue-router動態路由匹配
4.1 動態路由匹配
- 需求:點擊不同的用戶連接,顯示對應的用戶信息
- 定義如下路由鏈接和路由規則,是否可行?
image.png
動態路由匹配介紹:
image.png
- 匹配規則定義時,動態路由語法為:參數名,以冒號開頭,就代表是動態匹配
- 路由組件定義時,獲取路由參數為:{{$route.params.參數名}}
- $route.params.是固定寫法
- Vue實例的屬性,都是
el
// 創建 vm 實例對象
const vm = new Vue({
// 指定控制的區域
el: '#app',
data: {},
// 掛載路由實例對象
// router: router
router
})
- 創建Vue實例時,傳遞的參數有:el,data,router
- 那么vm有了
data,$router屬性
- 但是獲取動態參數,是{{$route.params.參數名}}
代碼:
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<!-- 導入 vue 文件 -->
<script src="./lib/vue_2.5.22.js"></script>
<script src="./lib/vue-router_3.0.2.js"></script>
</head>
<body>
<!-- 被 vm 實例所控制的區域 -->
<div id="app">
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link to="/user/3">User3</router-link>
<router-link to="/register">Register</router-link>
<!-- 路由占位符 -->
<router-view></router-view>
</div>
<script>
const User = {
template: '<h1>User 組件 -- 用戶id為: {{$route.params.id}}</h1>'
}
const Register = {
template: '<h1>Register 組件</h1>'
}
// 創建路由實例對象
const router = new VueRouter({
// 所有的路由規則
routes: [
{ path: '/', redirect: '/user'},
{ path: '/user/:id', component: User },
{ path: '/register', component: Register }
]
})
// 創建 vm 實例對象
const vm = new Vue({
// 指定控制的區域
el: '#app',
data: {},
// 掛載路由實例對象
// router: router
router
})
</script>
</body>
4.2 路由組件傳遞參數
介紹:
image.png
- 就是在組件中想要獲取路由參數,需要通過{{$route.params.id}}來獲取,比較麻煩
4.2.1 props的值為布爾類型
image.png
- 路由定義規則中:props:true,代表給動態參數id,開啟props傳參(其實就是通過props方式傳遞參數)
- 路由組件定義中:通過props接收參數
- 這樣就不用通過{{$route.params.id}}獲取
- 其實這個跟之前的組件通過屬性傳遞數據是類似的:
<User id='1'></User>
這個1就會傳遞給User組件的props屬性id
代碼:
<body>
<!-- 被 vm 實例所控制的區域 -->
<div id="app">
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link to="/user/3">User3</router-link>
<router-link to="/register">Register</router-link>
<!-- 路由占位符 -->
<router-view></router-view>
<User id='1'></User>
</div>
<script>
const User = {
props: ['id'],
template: '<h1>User 組件 -- 用戶id為: {{id}}</h1>'
}
const Register = {
template: '<h1>Register 組件</h1>'
}
// 創建路由實例對象
const router = new VueRouter({
// 所有的路由規則
routes: [
{ path: '/', redirect: '/user'},
{ path: '/user/:id', component: User, props: true },
{ path: '/register', component: Register }
]
})
// 創建 vm 實例對象
const vm = new Vue({
// 指定控制的區域
el: '#app',
data: {},
// 掛載路由實例對象
// router: router
router
})
</script>
</body>
內部原理:
image.png
4.2.2 props的值為對象類型
- 介紹:
image.png
- uname的lisi傳遞給User組件中props的uname,age的12傳遞給User組件中props的age
- 這時的id就無法獲取了,所以id在這種方式中就廢了
- 只有props為true時,才會將:id作為參數傳遞給User
代碼:
<body>
<!-- 被 vm 實例所控制的區域 -->
<div id="app">
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link to="/user/3">User3</router-link>
<router-link to="/register">Register</router-link>
<!-- 路由占位符 -->
<router-view></router-view>
</div>
<script>
const User = {
props: ['id', 'uname', 'age'],
//這個id其實是拿不到值的
template: '<h1>User 組件 -- 用戶id為: {{id}} -- 姓名為:{{uname}} -- 年齡為:{{age}}</h1>'
}
const Register = {
template: '<h1>Register 組件</h1>'
}
// 創建路由實例對象
const router = new VueRouter({
// 所有的路由規則
routes: [
{ path: '/', redirect: '/user'},
{ path: '/user/:id', component: User, props: { uname: 'lisi', age: 20 } },
{ path: '/register', component: Register }
]
})
// 創建 vm 實例對象
const vm = new Vue({
// 指定控制的區域
el: '#app',
data: {},
// 掛載路由實例對象
// router: router
router
})
</script>
</body>
4.2.3 props的值為函數類型
- 介紹:
image.png
- props指定了一個箭頭函數:相當于如下代碼
``` props:function (route){
return {uname:'zs',age:20,id:route.params.id}
}```
- 箭頭函數返回了一個對象,對象中的數據,就是要傳遞的數據
- uname和age是定死的值
- router是箭頭函數的形參,系統在調用時會將$route傳遞進去
- id是通過route.params.id動態獲取到id參數的值
代碼:
<body>
<!-- 被 vm 實例所控制的區域 -->
<div id="app">
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link to="/user/3">User3</router-link>
<router-link to="/register">Register</router-link>
<!-- 路由占位符 -->
<router-view></router-view>
</div>
<script>
const User = {
props: ['id', 'uname', 'age'],
template: '<h1>User 組件 -- 用戶id為: {{id}} -- 姓名為:{{uname}} -- 年齡為:{{age}}</h1>'
}
const Register = {
template: '<h1>Register 組件</h1>'
}
// 創建路由實例對象
const router = new VueRouter({
// 所有的路由規則
routes: [
{ path: '/', redirect: '/user' },
{
path: '/user/:id',
component: User,
props: route => ({ uname: 'zs', age: 20, id: route.params.id })
},
{ path: '/register', component: Register }
]
})
// 創建 vm 實例對象
const vm = new Vue({
// 指定控制的區域
el: '#app',
data: {},
// 掛載路由實例對象
// router: router
router
})
</script>
</body>
5. vue-router命名路由
介紹:
image.png
- 這樣就不用在定義路由鏈接得時候,在to中寫具體的path了
- 有時候path比較復雜,用名字代替會更好一點
- 如果path中有參數,那么在to中就通過params來確定參數的值
- 相當于:
<router-link to="/user/123">User2</router-link>
代碼:
<body>
<!-- 被 vm 實例所控制的區域 -->
<div id="app">
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link :to="{ name: 'user', params: {id: 3} }">User3</router-link>
<!--原來寫法,可能你會更喜歡原來的寫法,但是如果path比較復雜時,用命名路由會更好-->
<router-link to="/user/3">User2</router-link>
<router-link to="/register">Register</router-link>
<!-- 路由占位符 -->
<router-view></router-view>
</div>
<script>
const User = {
props: ['id', 'uname', 'age'],
template: '<h1>User 組件 -- 用戶id為: {{id}} -- 姓名為:{{uname}} -- 年齡為:{{age}}</h1>'
}
const Register = {
template: '<h1>Register 組件</h1>'
}
// 創建路由實例對象
const router = new VueRouter({
// 所有的路由規則
routes: [
{ path: '/', redirect: '/user' },
{
// 命名路由
name: 'user',
path: '/user/:id',
component: User,
props: route => ({ uname: 'zs', age: 20, id: route.params.id })
},
{ path: '/register', component: Register }
]
})
// 創建 vm 實例對象
const vm = new Vue({
// 指定控制的區域
el: '#app',
data: {},
// 掛載路由實例對象
// router: router
router
})
</script>
</body>
6. vue-router編程式導航
6.1 頁面導航的兩種方式
image.png
- 聲明式導航,其實就是html實現導航
- 編程時導航,其實就是js代碼實現導航(location.href就是js代碼)
- 頁面導航,其實就是頁面跳轉
6.2 編程導航
-
基本用法
image.png
- push跳轉錨點
- go前進后退,參數n一個數字,代表前進后退幾個界面
- n,代表前進n個界面
- -n,代表后退n個界面
代碼:
<body>
<!-- 被 vm 實例所控制的區域 -->
<div id="app">
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link :to="{ name: 'user', params: {id: 3} }">User3</router-link>
<router-link to="/register">Register</router-link>
<!-- 路由占位符 -->
<router-view></router-view>
</div>
<script>
const User = {
props: ['id', 'uname', 'age'],
template: `<div>
<h1>User 組件 -- 用戶id為: {{id}} -- 姓名為:{{uname}} -- 年齡為:{{age}}</h1>
<button @click="goRegister">跳轉到注冊頁面</button>
</div>`,
methods: {
goRegister() {
this.$router.push('/register')//跳轉到注冊頁面(錨點),可以看下效果
}
},
}
const Register = {
template: `<div>
<h1>Register 組件</h1>
<button @click="goBack">后退</button>
</div>`,
methods: {
goBack() {
this.$router.go(-1)//-1:后退1個界面
}
}
}
// 創建路由實例對象
const router = new VueRouter({
// 所有的路由規則
routes: [
{ path: '/', redirect: '/user' },
{
// 命名路由
name: 'user',
path: '/user/:id',
component: User,
props: route => ({ uname: 'zs', age: 20, id: route.params.id })
},
{ path: '/register', component: Register }
]
})
// 創建 vm 實例對象
const vm = new Vue({
// 指定控制的區域
el: '#app',
data: {},
// 掛載路由實例對象
// router: router
router
})
</script>
</body>
6.3 push參數 (了解)
-
介紹
image.png
- 跟route-link是一樣的作用,都是實現頁面跳轉
- 所以push中可以直接寫path路徑(路由),也可以寫命名路由
- 相當于:
<!--前兩個對應這個 -->
<router-link to="/home">User1</router-link>
<!--#push中的name應該也不帶斜杠才對-->
<router-link :to="{ name: 'user', params: {userId: 123} }">User123</router-link>
<router-link to="/register?uname=lisi">Register</router-link>