一、 路由
1. 什么是路由
(1)路由就是一種映射關(guān)系早抠。
(2)后端路由:url與后端資源的一 一對應(yīng)的關(guān)系
(3)前端路由:用戶事件與事件處理函數(shù)一 一對應(yīng)的關(guān)系
2.實現(xiàn)簡易前端路由
(1)前端路由是基于hash值的變化實現(xiàn)的鲫竞,這里的hash值指的是 url的hash值昵济,也就是界面的錨點。
(2)比如點擊頁面中的菜單或者按鈕改變URL的hash值窝稿,根據(jù)hash值的變化來控制組件的切換楣富。
(3)核心實現(xiàn)依靠 window.onhashchange 事件,監(jiān)聽hash值的變化伴榔。location.hash 可以獲取到最新的hash值纹蝴。
window.onhashchange = function(){
location.hash
}
(4)<component> 標(biāo)簽相當(dāng)于一個組件調(diào)用的占位符。通過綁定 v-bind:is 屬性踪少,動態(tài)控制此處調(diào)用哪個組件塘安。 (重點)
這個標(biāo)簽再父組件調(diào)用子組件時也可以用。
<component :is="comName"></component>
<div class="box">
<a href="#yule">娛樂</a>
<a href="#caijing">財經(jīng)</a>
<a href="#keji ">科技</a>
<a href="#junshi">軍事</a>
<component v-bind:is="change"></component>
</div>
<script>
// 子組件
var yule = {
template: `<h1>娛樂頭條</h1>`,
};
var caijing = {
template: `<h1>財經(jīng)頻道</h1>`,
};
var keji = {
template: `<h1>科技在線</h1>`,
};
var junshi = {
template: `<h1>軍事理論</h1>`,
};
// vue實例對象--父組件
var vm = new Vue({
el: '.box',
data: {
change: 'yule',
},
components: {
yule: yule,
caijing: caijing,
keji: keji,
junshi: junshi,
},
});
// 監(jiān)聽頁面的hash值的變化
window.onhashchange = function () {
var x = location.hash.slice(1);
switch (x) {
case 'keji':
vm.change = 'keji';
break;
case 'yule':
vm.change = 'yule';
break;
case 'caijing':
vm.change = 'caijing';
break;
case 'junshi':
vm.change = 'junshi';
break;
}
};
</script>
二秉馏、 vue-router
vue-router官網(wǎng):https://router.vuejs.org/zh/
1. 什么是 vue-router
① 它是一個Vue.js官方提供的路由管理器耙旦。
② Vue Router和Vue.js非常契合,可以一起方便的實現(xiàn)SPA(single page web application,單頁應(yīng)用程序)應(yīng)用程序的開發(fā)
③ Vue Router依賴于Vue萝究,所以需要先引入Vue.js免都,再引入Vue Router.js
2. Vue Router的特性
- 支持H5歷史模式或者h(yuǎn)ash模式
- 支持嵌套路由
- 支持路由參數(shù)
- 支持編程式路由
- 支持命名路由
3. 路由的基本使用
① 導(dǎo)入js文件。(項目中用import關(guān)鍵字引入)
必須先引入vue.js帆竹,再引入vue-router.js绕娘。
<!-- 1. 引入文件 -->
<script src="js/vue_2.5.22.js"></script>
<script src="js/vue-router_3.0.2.js"></script>
② 添加 路由鏈接。(項目中多用編程式導(dǎo)航)
<!-- 2. 添加路由鏈接 -->
<!-- 整個標(biāo)簽會被渲染成a鏈接栽连。 -->
<router-link to="/user">User</router-link>
<router-link to="/register">Register</router-link>
③ 添加 路由占位符(最后路由展示的組件就會在占位符的位置顯示)
<!-- 3.添加路由占位符 -->
<!-- 將來通過路由規(guī)則匹配到的組件险领,會被渲染到這里 -->
<router-view></router-view>
④ 定義 路由組件(項目中每個.vue文件都是組件)
- 路由組件全局定義,不需要使用 Vue.component秒紧,也不用再vue實例對象中掛載绢陌。
- 路由組件中的data 數(shù)據(jù)格式為:data( ) { return { } }。
- 需要在vue實例對象中掛載 路由實例對象熔恢。
// 4.創(chuàng)建路由組件
const User = {
data() {
return { name: "吳磊" }
},
template: `<h1>user</h1>`,
};
const Register = {
template: `<h1>register</h1>`,
};
⑤ 創(chuàng)建路由實例并配置 路由規(guī)則脐湾。(項目中將這部分單獨寫到一個.js文件)
- 路由規(guī)則【routes】是一個數(shù)組,每個數(shù)組元素都是一個配置對象叙淌。
- 每個配置對象至少有兩個屬性:path 秤掌、component愁铺。
- path的值是路由鏈接的hash值;component的值是路由組件的名稱闻鉴。(不能加引號)
// 5. 創(chuàng)建路由實例并配置路由規(guī)則
var router = new VueRouter({
// 路由規(guī)則【routes】是一個數(shù)組茵乱,每個數(shù)組元素都是一個配置對象。
// 每個配置對象至少有兩個屬性:path 孟岛、component瓶竭。
// path的值是路由鏈接的hash值;component的值是路由組件的名稱渠羞。(不能加引號)
routes: [
{ path: '/user', component: User },
{ path: '/register', component: Register },
],
});
⑥ 將路由掛載到Vue實例對象中
// 6. 將路由掛載到vue實例對象中
var vm = new Vue({
el: '.box',
router: router,
});
⑦ 如果 是在項目中在验,應(yīng)該全局注冊路由,這樣在任何一個vue組件 中都能使用this.$router
Vue.use(VueRouter)
示例如下:
<div class="box">
<!-- 2. 添加路由鏈接 -->
<!-- 整個標(biāo)簽會被渲染成a鏈接堵未。 -->
<router-link to="/user">User</router-link>
<router-link to="/register">Register</router-link>
<!-- 3.添加路由占位符 -->
<!-- 將來通過路由規(guī)則匹配到的組件腋舌,會被渲染到這里 -->
<router-view></router-view>
</div>
<script>
// 4.創(chuàng)建路由組件
const User = {
template: `<h1>user</h1>`,
};
const Register = {
template: `<h1>register</h1>`,
};
// 5. 創(chuàng)建路由實例并配置路由規(guī)則
var router = new VueRouter({
// 路由規(guī)則【routes】是一個數(shù)組,每個數(shù)組元素都是一個配置對象渗蟹。
// 每個配置對象至少有兩個屬性:path 块饺、component。
// path的值是路由鏈接的hash值雌芽;component的值是路由組件的名稱授艰。(不能加引號)
routes: [
{ path: '/user', component: User },
{ path: '/register', component: Register },
],
});
// 6. 將路由掛載到vue實例對象中
var vm = new Vue({
el: '.box',
router: router,
});
</script>
三、路由的更多使用規(guī)則
1. 路由重定向
{ path: '/', redirect: '/user' }
在路由規(guī)則中世落,使用 redirect 屬性淮腾,可以實現(xiàn)路由重定向。當(dāng)訪問 " / " 根路徑時屉佳,強制跳轉(zhuǎn)到 " /user " 頁面谷朝。
注意:
① 如果重定向的是一個子路由,則該路由的父級路由組件也會被渲染出來武花。
② 子路由可以把path屬性設(shè)置為空圆凰,父路由組件渲染時默認(rèn)顯示這個子路由組件。
2 .路由嵌套
① 子路由的 路由鏈接 和 路由占位符 体箕,寫到父級路由的組件模板中专钉。
② 子路由的 組件 直接全局定義。
③ 子路由的 路由規(guī)則數(shù)組 累铅,寫到父級路由的規(guī)則配置對象中跃须。
注意:
① 一級父路由的路徑以 "/" 開頭;
② 子路由的path路徑可以帶上父路由路徑 /father/children 娃兽,
③ 也可以只寫子路由路徑菇民,但是不能再以 / 開頭。
④ 根路由已經(jīng)掛載到vue實例對象上了,子組件不需要操作玉雾。
<div class="box">
<!-- 2. 父級路由鏈接 -->
<router-link to="/user">User</router-link>
<!-- 3.父級路由占位符 -->
<router-view></router-view>
</div>
<script>
// 4.父級路由組件
const User = {
template: `<div>
<h1>user</h1>
<router-link to="/user/table1">table1</router-link>
<router-link to="/user/table2">table2</router-link>
<router-view></router-view>
</div>`,
};
// 子級路由組件
const child1 = {
template: '<h3>table1</h3>',
};
const child2 = {
template: '<h3>table2</h3>',
};
// 5. 創(chuàng)建路由實例并配置路由規(guī)則
var router = new VueRouter({
routes: [
{
path: '/user',
component: User,
children: [
{ path: '/user/table1', component: child1 },
{ path: '/user/table2', component: child2 },
],
},
],
});
// 6. 將路由掛載到vue實例對象中
var vm = new Vue({
el: '.box',
router: router,
});
</script>
3. 動態(tài)匹配路由(重要)
① 如果多個路由鏈接的 hash值 非常相似,可以在 路由規(guī)則 中轻要,讓多個 path 值(路由鏈接的hash值) 對應(yīng)一個componet (路由組件)复旬。
② 也就是 多個路由鏈接 對應(yīng)一個 路由規(guī)則。
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link to="/user/3">User3</router-link>routes: [{ path: '/user/:uid冲泥?', component: User }],
動態(tài)參數(shù)uid后面的 驹碍?表示,訪問也面時凡恍,這個動態(tài)參數(shù)可以傳遞志秃,也可以不傳遞。
實例:不同頻道有各自的文章列表數(shù)據(jù)嚼酝,我們根據(jù)頻道的id生成了多個組件去渲染數(shù)據(jù)浮还。如果想要用路由跳轉(zhuǎn)到各個組件頁面,就要用動態(tài)路由闽巩。否則多個頻道對應(yīng)對個組件钧舌,就要定義多個路由。
4. 動態(tài)匹配路由傳參(重要)
- 路由規(guī)則對象 向 路由組件 傳遞參數(shù)涎跨。
(1)路由組件可以通過 $.route.params.uid 獲得路由規(guī)則對象中的 動態(tài)參數(shù) uid洼冻。
template: "<h1>路由的id為{{$route.params.uid}}</h1>"
① this.$route.query.id 可以獲取路由規(guī)則中的查詢參數(shù)。
② this.$router.options.routes 可以獲得路由(規(guī)則)對象隅很。
(2)在路由規(guī)則對象中撞牢,添加 props屬性。props屬性值為 true 時叔营,路由組件可以通過 props數(shù)組 獲得路由規(guī)則對象中的 動態(tài)參數(shù) uid屋彪。
// 4.創(chuàng)建路由組件
const User = {
props: ['uid'],
template: `<h1>路由的id為{{uid}}</h1>`,
};
// 5. 創(chuàng)建路由實例并配置路由規(guī)則
var router = new VueRouter({
// 在路由規(guī)則中,讓多個路由鏈接對應(yīng)一個路由組件绒尊。
routes: [{ path: '/user/:uid', component: User, props: true }],
});
(3)props屬性值為 一個對象 時撼班,路由組件可以通過 props數(shù)組 獲得路由規(guī)則中的 靜態(tài)參數(shù)。
// 4.創(chuàng)建路由組件
const User = {
props: ['uname','age'],
template: `<h1>姓名:{{uname}},年齡:{{age}}</h1>`,
};
// 5. 創(chuàng)建路由實例并配置路由規(guī)則
var router = new VueRouter({
// 在路由規(guī)則中垒酬,讓多個路由鏈接對應(yīng)一個路由組件砰嘁。
routes: [
{
path: '/user/:uid',
component: User,
props: { uname: '吳磊', age: '22' },
},
],
});
(4)props屬性值為 一個函數(shù) 時,路由組件可以通過 props數(shù)組 獲得路由規(guī)則中的 靜態(tài)參數(shù)和動態(tài)參數(shù)勘究。
// 4.創(chuàng)建路由組件
const User = {
props: ['uname', 'age', 'uid'],
template: `<h1>姓名:{{uname}},年齡:{{age}},id:{{uid}}</h1>`,
};
// 5. 創(chuàng)建路由實例并配置路由規(guī)則
var router = new VueRouter({
// 在路由規(guī)則中矮湘,讓多個路由鏈接對應(yīng)一個路由組件。
routes: [
{
path: '/user/:uid',
component: User,
// 箭頭函數(shù)只有一句代碼,并且是返回值信息,則可以省略花括號敦间。
props: (route) => ({
uname: '吳磊',
age: '22',
uid: route.params.uid,
}),
},
],
});
5. 命名路由
① 在 路由規(guī)則對象 中怖侦,添加 name 屬性挂捅,為這個路由規(guī)則命名馅扣。
② 在 路由鏈接 中脐恩,為 to屬性綁定 一個對象舍肠, 代替 url地址 向族。
<router-link v-bind:to="{name:'user',params:{uid:3}}">User3</router-link>
routes: [
{
name: 'user',
path: '/user/:uid',
component: User,
},
],
<div class="box">
<!-- 2. 路由鏈接 -->
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<!-- 命名路由 -->
<router-link v-bind:to="{name:'user',params:{uid:3}}">User3</router-link>
<!-- 3.添加路由占位符 -->
<router-view></router-view>
</div>
<script>
// 4.創(chuàng)建路由組件
const User = {
props: ['uname', 'age', 'uid'],
template: `<h1>姓名:{{uname}},年齡:{{age}},id:{{uid}}</h1>`,
};
// 5. 創(chuàng)建路由實例并配置路由規(guī)則
var router = new VueRouter({
routes: [
{
// 命名路由
name: 'user',
path: '/user/:uid',
component: User,
},
],
});
// 6. 將路由掛載到vue實例對象中
var vm = new Vue({
el: '.box',
router: router,
});
6. 編程式導(dǎo)航
聲明式導(dǎo)航:通過點擊鏈接實現(xiàn)導(dǎo)航的方式呵燕,叫做聲明式導(dǎo)航 例如:普通網(wǎng)頁中的 鏈接 或 vue 中的 <router-link></router-link>
編程式導(dǎo)航:通過調(diào)用JavaScript形式的API實現(xiàn)導(dǎo)航的方式,叫做編程式導(dǎo)航 例如:普通網(wǎng)頁中的 location.href
(1)常用的編程式導(dǎo)航的API
this.$router.push('hash地址') 跳轉(zhuǎn)到指定頁面
this.$router.go( ) 頁面的前進與倒退
(2)push 方法可以接收的參數(shù)
router.push('/home') // 字符串(路徑名稱)
router.push({ path: '/home' }) // 對象
router.push({ name: 'user', params: { userId: 123 }}) // 命名的路由(傳遞參數(shù))
router.push({ path: '/register', query: { uname: 'lisi' }}) // 帶查詢參數(shù)件相,變成 /register?uname=lisi
<div class="box">
<!-- 2. 路由鏈接 -->
<router-link to="/user">User</router-link>
<router-link to="/register">Register</router-link>
<!-- 3.添加路由占位符 -->
<router-view></router-view>
</div>
<script>
// 4.創(chuàng)建路由組件
const User = {
template: `<div>
<h1>User部分</h1>
<button v-on:click="handle">跳轉(zhuǎn)到Register頁面</button>
</div>`,
methods: {
handle: function () {
// 用編程的方式控制路由跳轉(zhuǎn)
this.$router.push('/register');
},
},
};
const Register = {
template: `<div>
<h1>Register部分</h1>
<button v-on:click="handle">回退</button>
</div>`,
methods: {
handle: function () {
// 用編程的方式控制路由跳轉(zhuǎn)
this.$router.go(-1);
},
},
};
// 5. 創(chuàng)建路由實例并配置路由規(guī)則
var router = new VueRouter({
routes: [
{ path: '/user', component: User },
{ path: '/register', component: Register },
],
});
// 6. 將路由掛載到vue實例對象中
var vm = new Vue({
el: '.box',
router: router,
});
</script>
7. 路由的導(dǎo)航守衛(wèi)(重要)
作用:路由導(dǎo)航守衛(wèi)可以判斷當(dāng)前狀態(tài)下是否有token 令牌再扭。從而限制用戶直接輸入地址訪問頁面。
(1)前置守衛(wèi)
router.beforeEach(function(to, from, next) {}
to 代表要去的路由夜矗;
from 代表從哪個路由來泛范;
next 是一個鉤子函數(shù),必須進行調(diào)用紊撕。
(2)后置守衛(wèi)
router.afterEach(function() {})
注意:這里的router使用的是 路由的實例對象罢荡,也就是包含了路由規(guī)則的路由對象。
8. 路由的權(quán)限處理
(1)登錄時路由權(quán)限處理(訪問權(quán)限)
① 動態(tài)路由不要直接掛載到router實例對象上对扶。
② 當(dāng)前登錄用戶的個人信息里柠傍,有一個屬性保存了當(dāng)前用戶的 權(quán)限標(biāo)識,這個權(quán)限標(biāo)識和 動態(tài)路由對象里的name屬性值 一 一對應(yīng)辩稽。
③ 動態(tài)路由的權(quán)限處理可以在vuex中進行惧笛。state數(shù)據(jù)中保存當(dāng)前用戶所有的路由對象,用于渲染左側(cè)菜單逞泄;最重要的是患整,在actions中定義一個 篩選動態(tài)路由對象 的方法。
④ 在 路由導(dǎo)航守衛(wèi) 的權(quán)限攔截處喷众,拿到token令牌后調(diào)用actions方法各谚,可以得到用戶的 動態(tài)路由對象。然后用Vue.router提供的 router.addRoutes(路由規(guī)則對象數(shù)組) 方法到千,為router實例對象追加動態(tài)路由對象昌渤。
注意:用router.addroutes()方法后,要手動 next(to.path)憔四。
(2)登出時重置路由權(quán)限(訪問權(quán)限)
① 我們在登錄時為router實例對象添加了動態(tài)路由膀息,必須在退出登錄時 重置,否則下一個用戶登錄后會繼續(xù)使用上一個用戶的權(quán)限了赵。路由模塊 提供了方法潜支,只需要在 退出登錄 時調(diào)用即可。
// 重置路由柿汛。新建一個路由實例冗酿,把新路由的路由規(guī)則對象(只有個靜態(tài)路由)賦值給老路由實例。
export function resetRouter () {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
② 左側(cè)菜單的渲染使用的是vuex中的路由數(shù)據(jù),退出登錄 時也要 重置裁替。
(3)功能權(quán)限
① 用戶擁有了動態(tài)路由项玛,就能訪問對應(yīng)的頁面,但是頁面中的某些按鈕是否能點擊等操作弱判,受控于訪問權(quán)限下的 功能權(quán)限襟沮。
②用 Vue.mixin( { }) ,給所有的vue組件 混入一個 methods方法,這個方法根據(jù) 功能點的權(quán)限標(biāo)識 和用戶信息里的 功能權(quán)限標(biāo)識 進行比對裕循,返回一個布爾值。
// 全局的混入對象
// 導(dǎo)入vuex
import store from '@/store'
export default {
methods: {
// 這里的參數(shù)key是系統(tǒng)某個功能的【權(quán)限標(biāo)識】
checkPermission (key) {
// 這是vuex中保存的用戶數(shù)據(jù)净刮,里面有當(dāng)前用戶的【功能權(quán)限標(biāo)識】
// store.state.user.userInfo.roles.points
const { userInfo } = store.state.user
// 如果用戶有【功能權(quán)限標(biāo)識】數(shù)組剥哑,并且有值,就進行篩選判斷
if (userInfo.roles.points && userInfo.roles.points) {
return userInfo.roles.points.some(item => item === key)
}
return false// 如果連if都進不去淹父,必定沒有權(quán)限
}
}
}
③ 給組件中的按鈕v-bind綁定這個方法株婴,通過返回值判斷當(dāng)前用戶是否可以使用這個按鈕。
<el-button
size="small"
type="primary"
:disabled="!checkPermission('POINT-USER-ADD')"
>新增員工</el-button>
9.路由傳參
(1)編程式導(dǎo)航傳參
① params形式 :參數(shù)不顯示在地址欄
this.$router.push({name: "department",params:{userId:this.num})
② query形式:參數(shù)在地址欄內(nèi)顯示
this.$router.push({path:"/department",query:{name:"馬冬梅",age:30})
③ 在組件內(nèi)獲取
this.$route.params.userId 或者 this.$route.query.name 進行獲取
注意:跳轉(zhuǎn)到 新開頁 時暑认,用params傳遞的參數(shù)是獲取不到的困介。可以用 query傳參蘸际;或者將params參數(shù)寫到路由對象里座哩。
(2)聲明式導(dǎo)航傳參
補充
① 有了前端路由,組件就定義在路由里面粮彤。最外面是一個根路由組件根穷。
② 為根路由組件 配置路由規(guī)則。
③ 把根路由組件 掛載 到vue實例對象上导坟。
④ 最后在vue實例對象控制的HTML結(jié)構(gòu)中 添加路由占位符屿良,渲染出整個根路由組件。
前端路由惫周,就是通過 路由鏈接 生成一個 a標(biāo)簽尘惧,通過 路由組件 生成主體內(nèi)容,然后用 路由規(guī)則 把這兩項進行綁定递递。最后通過 路由占位符 指定渲染的位置喷橙。
- 在組件中,this.$router 獲取到的是路由對象登舞,可以調(diào)用路由的 push() 重慢、go()、back()方法逊躁。 this.$route 獲取到的是路由規(guī)則中的路徑參數(shù)似踱,可以獲取到 path、query 等。