概述
vue-router是vue-cli中管理路由的模塊
通過URL,實現(xiàn)URL和組件之間的一一對應(yīng),通過URL進行組件 切換
應(yīng)用場景:
單頁面應(yīng)用 single page application(SPA) 移動端應(yīng)用很廣泛, 沒有真實的頁面跳轉(zhuǎn),只是針對不用URL在頁面內(nèi)容區(qū)域做了不同的渲染
只是加載一次JS、CSS文件,降低了頁面切換時候的 HTTP請求
安裝方式
1.一般在vue-cli初始化(vue init webpack 項目名稱)時候,會有提示 是否安裝vue-router,選擇y回車,即可安裝
2.后續(xù)手動安裝,命令行到指定目錄
輸入:
npm install vue-router --save //安裝vue-router并添加到依賴
使用
以將代碼放置在入口文件main.js為例
import Vue from 'vue'
import App from './app'
//1.引入模塊
import VueRouter from 'vue-router'
//2.將vue-router作為Vue的插件
Vue.use(VueRouter)
//3.創(chuàng)建vue-router實例
let router = new VueRouter({
...
})
//4.將路由配置信息router掛載到Vue實例
new Vue({
el: '#app',
router,
template: '<app />'
components:{
App //App為跟組件 App.vue
}
})
配置路由
let router = new VueRouter({ ... })
說明:為什么命名router
router是我們的路由實例,命名為變量router是為了方便簡寫,在Vue實例上有個鍵名叫router,兩者相同則可以寫一個鍵名即可
1.簡單配置路由
new VueRouter({
mode:'history', //模式分為 hash,history兩種,默認為hash
linkActiveClass:'xxx', //當前處在激活狀態(tài)下的router-link標簽上的狀態(tài)class名
scrollBehavior(to,from,saveposition){ //滑動信息
...
},
routes:[ //路由調(diào)整信息
{
path:'/', //這個是路徑
component:xxx, //這個是對應(yīng)import過來的單文件組件,作為模板
alias:'/index', //訪問另一個路徑,扔可以訪問,但是不會觸發(fā)按鈕的激活類名
name:'indexpage' ,
meta:{ //定義針對當前路由的自定義數(shù)據(jù)
needlogin:true
}
},{
path:'/about',
component:xxx
},{
path:'*', //通配符,標識沒有配置路由的路徑情況,一般作為404
redirect:{ //重新定向到一個已經(jīng)存在的路由路徑
path:'xxxx'
}
}
]
})
另外,配置路由,引入模板時候,在vue-cli中 @標識src文件夾,可以在webpack.base.conf.js 查看其聲明
2.關(guān)于配置路由中的mode選擇
new VueRouter({
mode:'hash', //如果選擇hash模式,鏈接中需要帶#
routes:[
...
]
})
建議:
一般低版本瀏覽器使用hash模式
高版本瀏覽器使用history模式
3.關(guān)于配置路由中的重定向redirect
redirect((to)=>{ //通過箭頭函數(shù),參數(shù)to,可以獲取path路徑,可以更加豐富我們重定向的邏輯
if(to.path=='xxx'){
return '/my'; //跳轉(zhuǎn)到我的
}else{
return '/'; //跳轉(zhuǎn)到首頁
}
})
//redirect書寫的方式
redirect:'/about'
redirect:{path:'/about'}
redirect:{name:'xxx'} //通過routes中的name,也可以定位
4.存在二級路徑嵌套時候
默認顯示第一項的需求
在二級嵌套中,如果希望父路由默認顯示第一個子路由信息,且子路由為激活狀態(tài)
則可以將父路由path:'',將子路由的第一項path設(shè)置為父路由原有path
...
{
path: '/about',
component: 'xxx',
children:[
{
path:'/about/xxx', //二級子菜單
component:'xxxx'
}
]
}
...
使用children嵌套數(shù)據(jù),將子路由對象放進去
5.路由是我們配置瀏覽器跳轉(zhuǎn)的基本配置,在模板頁面中我們需要使用連接來觸發(fā)
<router-link>我是個按鈕</router-link>
router-link屬性:
to="xxx" //相當于a標簽的href,填寫跳轉(zhuǎn)鏈接
tag="li" //將<router-link>渲染為什么標簽,以便瀏覽器去渲染
event="hover" //如果要添加一個觸發(fā)事件,則用event來聲明,默認click
active-class="xxx"
//如果標簽對應(yīng)的,路由路徑為當前狀態(tài),則vue-router會默認為其添加激活的狀態(tài)類名
//如果你想自定義自己的激活狀態(tài)class名,則用這個
//另外,自定義狀態(tài)類名有2個位置,一個在路由配置中,一個在這個觸發(fā)按鈕上,
//同時配置,按鈕的優(yōu)先級高,會剔除掉路由上的激活狀態(tài)配置類名
exact
//如果不采用相對于根路徑 /xxx 那么有可能存在,父路由,子路由同時處于激活class名狀態(tài)下
//此時,添加exact 嚴格模式,以便只有一個路由顯示激活class名
6.對應(yīng)path有router-link,對應(yīng)的component,應(yīng)該渲染到這里<router-view>
<router-link to="xxxx" tag="li">
<a>按鈕1</a> //如果router-link要嵌套a標簽,則a標簽不用再寫href了
</router-link>
<router-link to="xxxx" tag="li">
<a>按鈕2</a>
</router-link>
//多個按鈕對應(yīng)一個router-view
<router-view></router-view>
7.命名視圖
在路由配置的routes中 path和component是一一對應(yīng)的,
如果我們希望某一個path對應(yīng)多個component時候
如:
//在路由配置文件中
path:"/about",
components:{ //注意 components 是復(fù)數(shù)形式
default: "模板1", //不寫name的view-router為default
slider: "模板2"
}
//在單文件組件中
//當我們訪問 /about 時候,下面2個router-view會同時顯示
<router-view></router-view>
<router-view name="slider"></router-view>
//在router-view中可以添加class名,
<router-view class="father-box"></router-view> //router-view中的所有結(jié)構(gòu)都有一個父級class名為father-box
//在單文件組件中
<template>
<div class="son-box">
<p>hello</p>
</div>
</template>
//渲染后
<div class="father-box son-box"> //類名會進行合并
<p>hello</p>
</div>
8.路由配置中的scrollBehavior
在頁面onload或者瀏覽器前進,后退時候觸發(fā)
scrollBehavior(to,from,saveposition ){
//to 目標路由
//from 當前路由
//saveposition 當前位置
//可以將當前 saveposition 作為返回值,達到頁面跳轉(zhuǎn),返回后恢復(fù)滾動條位置的效果
//滾動條滑動頂部位置
return { x: 0, y: 0 };
}
8.動態(tài)路由
在路由配置中,所有的path都是以一個可預(yù)測的狀態(tài)存在
如果我們希望添加一個格式,不清楚具體數(shù)據(jù),需要使用動態(tài)路由
//在路由配置中
...
{
path:'/students/:userId?', //其可以匹配 /students,/students/1,/students/2
component:'xxx'
}
...
//在單文件組件頁面
通過 this.$route.params.userId 可以獲取其信息,使得后續(xù)邏輯上更加豐富
9.路由的自定義屬性
...
{
path:'xxxx',
component:'xxxx',
meta:{
needlogin:true
}
}
...
//在單文件組件中,我們可以通過$route中獲取
this.$route.meta.needlogin
- 動態(tài)路由的傳參的新方式,配置
props: true
- 通常方式
//---路由部分
routes:[
{
path:'/categories/edit/:id?'
component:'xxx'
}
]
//---單文件組件中
created(){
console.log(this.$route.params.id);
}
- 新的傳遞params方式:
路由中props為true,代表將連接中任何參數(shù),以props方式注入到新組件中去
//---路由部分
routes:[
{
path:'/categories/edit/:id?'
component:'xxx',
props: true
}
]
//---單文件組件中
props:[
'id'
]
router 與 $route
router是我們創(chuàng)建的VueRouter實例
$route是當前單文件組件的路由實例
router實例方法 實現(xiàn) 【編程式導(dǎo)航】
//直接跳轉(zhuǎn)
router.push('/about')
router.push({ path: '/about' })
//動態(tài)路由,單文件頁面通過 this.$route.params.userId 獲取傳遞信息
router.push({ name: 'about', params: { userId: '123' }})
//查詢字符串方式,用戶訪問有權(quán)限的頁面,直接跳轉(zhuǎn)到登錄頁,
//登錄完成后,通過this.$route.query.redirect 獲取用戶之前想去的頁面,然后通過push,再次跳轉(zhuǎn)
//實現(xiàn) 未登錄狀態(tài)->登錄->登錄后自動跳轉(zhuǎn)用戶之前想去的 權(quán)限限制頁面
router.push({ path: '/login', query: { redirect: '/user' }})
其他方法:
router.repalce( '/xxx' )
//將歷史記錄中的當前步驟替換掉,并且完成跳轉(zhuǎn)
router.go(number)
// 填寫具體數(shù)字,針對history的當前步數(shù),向前是負值,向后是正值,但是只能在歷史步數(shù)內(nèi),超過則不作操作
vue-router生命周期 鉤子
全局鉤子函數(shù)
所有路由進入,出去都會觸發(fā)此鉤子函數(shù)
- beforeEach
還沒有進入路由內(nèi),所有不能獲取vue實例
如果此時此刻想獲取,可以通過router.app方式,得到vue實例
let router = new VueRouter({...})
router.beforeEach(function(to,from,next){
console.log(to); //目標導(dǎo)航
console.log(from); //離開導(dǎo)航
next(); //執(zhí)行則路由跳轉(zhuǎn)
//實際例子,根據(jù)路由情況,判斷是否需要登錄
//根據(jù)目標路徑下的 自定義屬性meta(如果你設(shè)置了),如
...
{
path:'/xxx'
component:'xxx',
meta:{ //meta提供開發(fā)者掛載自定義數(shù)據(jù)
needLogin:true //xxx頁面需要登錄
}
}
...
//如果跳轉(zhuǎn)到xxx頁面,則跳轉(zhuǎn)到登錄/login,否則路由正常跳轉(zhuǎn)
if(to.meta.needLogin){
next('/login');
}else{
next();
}
})
- afterEach
rourer.afterEach(function(to,from){
//路由跳轉(zhuǎn)后,我們可以做一些操作
//例如: 根據(jù)path或者meta添加新屬性,去判斷,改變文檔標題
if(to.path=='/'){
window.document.title = 'xxx'
}else if{
...
}else{
...
}
});
局部鉤子函數(shù)
beforeEnter 針對某一個路由,進行處理
...,
{
path:'xxx'
component:'xxx',
beforeEnter(to,from,next){
//只是針對xxx這個path,做操作
next(); //next必須執(zhí)行,否則會卡住
}
},
...
單文件組件中的鉤子函數(shù)
優(yōu)先順序從【0】開始
<script>
data(){
return{
msg:'hello'
}
},
created(){
console.log("創(chuàng)建完成:");
console.log(this.$el);
},
beforeCreate(){ 【2】
//組件執(zhí)行的第一個鉤子函數(shù)
},
beforeRouteEnter(to,from,next){【1】
//訪問導(dǎo)航時候,執(zhí)行這個路由執(zhí)行的第一的函數(shù)
//這個時候組件還沒有初始化,無法訪問this
console.log(this) //undefined
next(function(vm){ //next中函數(shù)的參數(shù),參數(shù)vm就是vue實例
//vm就是當前組件實例
console.log(vm.msg); //'hello'
})
},
beforeRouteUpdata(to,from,next){
//這個是路由嵌套情況下,點擊子導(dǎo)航觸發(fā)
console.log('beforeRouteUpdata');
next(); //不寫這個鉤子函數(shù)不會繼續(xù)執(zhí)行
console.log(this) //可以訪問組件實例
},
beforeRouteLeave(to,from,next){
//離開主導(dǎo)航(主組件)時候觸發(fā)
}
</script>
路由的細節(jié)問題
- 同一個路由地址,query參數(shù)不同,點擊通過$router.push從當前路由地址,跳轉(zhuǎn)到當前路由地址,參數(shù)變化
//傳值
this.$router.push({path:"/menLink",query:{alert:"頁面跳轉(zhuǎn)成功"}})
//用query獲取值
<p>提示:{{this.$route.query.alert}}</p>
頁面不重新渲染的情況,只需要對 <router-view></router-view> 增加屬性key
<router-view :key="$route.fullPath" ></router-view>
1-2. 當兩個不同的path,對應(yīng)相同的component的時候;
在兩個路由之間切換,不會改變router-view視圖更新
如:
{
path: '/create',
component:Categories
},{
path: '/edit/:id',
component:Categories
}
解決方法:
綁定key屬性
<router-view :key="$route.path"></router-view>
1-3.當兩個相同的path,對應(yīng)相同的component的時候;
在兩個路由之間切換,不會觸發(fā)created的生命周期函數(shù),不會對router-view進行視圖更新
如:
{
path: '/article/:id',
component:Article
}
id=1 與 id=2 兩個情況,切換時候碰到
解決方法:
需要針對id進行watch,之后強制觸發(fā)created中的數(shù)據(jù)獲取函數(shù)
如:
watch:{
id : function(){
//請求對應(yīng)ID下的數(shù)據(jù),進行視圖渲染
this.getDataByIdFn();
}
},
created(){
//默認進入獲取
this.getDataByIdFn();
}
- ios 和 safari下,相同path但query修改,跳轉(zhuǎn)后,會出現(xiàn)頁面不渲染的情況,因此使用window.location.reload刷新頁面
this.$router
.push({ path: "/college", query: { DeptInfo: id } })
.then(() => {
window.location.reload();
});
生命周期相關(guān)
組件內(nèi)路由
- beforeRouteEnter
beforeRouteEnter(to, from, next){
// 無法獲取this,只能通過vm獲取
next(vm => {
vm.routeFrom = from.name
vm.routeTo = to.name
})
}
- beforeRouteLeave
beforeRouteLeave(to, from, next){
this.routeFrom = from.name
this.routeTo = to.name
}