雖然有很多
router
的相關文章了,但是那又怎麼樣,我就是要寫。
歡迎來我的Vue技術群交流:887516034
其實vuejs有一個叫做動態元件的東西,效果和路由有點相似,根據需求顯示不同的元件,但是在實際使用上,很小氣,就給人玩不爽,沒辦法像路由一樣程式設計式導航(push
,replace
),也沒有瀏覽器路徑的語義引導,動態元件更適合小規模的區域性tab,給大家秀一波用法
<template>
<div>
ul>li>tab1+tab2 @click="" <!-- >>>此處改變下面data中的tab值就可以切換了 -->
<!-- 此處相當於router-link效果,雖然沒有瀏覽器的url引導,但是可以自己寫麵包屑 -->
<component :is="tab"></component> <!-- 這裡就是router-view顯示區了 -->
</div>
</template>
<script>
import tab1 from 'path/to/tab1.vue' //相比vue-router要引入很多檔案 麻煩
import tab2 from 'path/to/tab2.vue'
//其實vue-router也引入檔案,但是在.vue檔案裡面引入那麼多就很難看
export default {
data(){
tab:'tab1' //預設顯示tab1
},
components:{
tab1,
tab2 //es6語法 物件中,鍵值相同可以這樣寫
}
}
</script>
複製程式碼
我們不提動態元件了,開始router了。常用的api,官網介紹的很詳細了。記得看官方教程,別忘了官方的api
路由的配置
不管是什麼路由的配置 還是vuex的配置等等,都有相應的規範,在普通js檔案,不按規範也不會怎麼樣,在ts檔案,就會報錯了。前提是有興趣玩ts。
// router/index.js
// 此處省略一堆 import
const router = new Router({
base:'/',
mode:'history',//default-->hash
routes:[],
scrollBehavior:()=>{
return {x:0,y:0}
}
})
複製程式碼
其實配置很簡單,就這麼一點。
base
瀏覽器url的字首,預設為'/'
,如果設定為'/some/'
,則執行專案,瀏覽器url都是'/some/...'
,不會對靜態檔案的引用產生影響,一般寫網站都會有域名,都可以把域名指向某個伺服器目錄,所以預設'/'
即可,如果是寫公司內部後臺管理,那麼不一定會用域名,可能就是某個ip下的某個目錄,比如打包後的檔案在111.22.33.44/admin
,這個時候路由的配置匹配瀏覽器路徑的時候,會從這個/admin
開始算,如果base還是預設的/
,那麼路由配置的routes
的path
就要全部加上/admin/
字首,並且router-link
和push
方法也要加上這個/admin
,很麻煩,但是隻要設定base
為'/admin/'
,路由內部配置以及所有相關的方法都可以忽視伺服器ip下的目錄名。這種情況,同樣也要配置webpack
的publicPath
也為/admin/
,這裡不細說了。
mode
這個太簡單了,一共三種模式,
hash
:瀏覽器會有‘#’符號,參考錨點效果,缺點很醜,但是相容性棒棒
history
:去除‘#’符號,讓url變好看,下面會講服務端配置。
abstract
:非瀏覽器環境,會強制使用這個模式,例如weex
history模式服務端配置
我個人和公司都是用nginx
,這裡就講nginx
,配置這個的原因是當你進入某個路由之後,再次重新整理頁面時(或者是瀏覽器直接輸入某個路由路徑時),當重新整理頁面,瀏覽器就會重新dns解析,tcp協議,這個時候會根據瀏覽器的url去伺服器找對應資源,當然我們vue-router
是為單頁面服務的,對應的url在服務端是肯定沒有靜態資源的,就會出現404,當配置了以下url重寫語句,注意是重寫,不是重定向,不改變url的情況重寫瀏覽器內容,重寫到index.html
,因為這個index.html
使我們專案的入口,index.html
裡面會讀取當時打包好的app.js
,就可以讀取到路由配置,以實現我們瀏覽器的url對應的路由頁面。
hash
模式不需要配置,因為瀏覽器會忽略#和?後面的引數
打包檔案在根目錄時,
location / {
try_files $uri $uri/ /index.html;
}
複製程式碼
打包檔案在非根目錄時,
location /admin {
try_files $uri $uri/ /admin/index.html;
}
複製程式碼
routes
核心路由配置,官網講的很詳細,我就講幾個注意點,所有自定義的配置,例如是否需要鑑權或者對應的icon等,需要規範化的話都寫在meta
物件中,
不規範的話 ,就和path
同級咯,隨意玩,玩壞了我不背鍋。
path
是必須指定的,name
需要唯一,不是必須。
routes
的配置遵循順序匹配,當url成功匹配,就不會再往下匹配,所以像403,404
的頁面應當寫在最後。
alias
別名的使用,當需要在指定router-view
顯示某個元件,並且希望瀏覽器url是自己想要的語義時使用
redirect
重定向,引數可以是路徑,也可以是物件(重定向到某個name),注意重定向是改變內容+改變url
scrollBehavior
這個滾動行為,老實說,感覺很蹩腳,本人基本沒有使用過,他控制的是body的滾動, 很多需求都是區域性滾動。如果的確是需要控制body滾動,參考官方文件即可。
路由的使用
路由的配置一開始只有根目錄/
,每寫一層children
就要寫一層router-view
,否則元件不顯示。每一個巢狀children
的層級和router-view
的層級都是一一對應的。
// router/index.js
const router = new Router({
routes:[
{
path:'/', //此時配置陣列的第一層級,即對應app.vue中的router-view
component:Home,// <<<----------------------------
children:[// |
{ // |
//此時第一層級出現children第二層級,------------
//那麼在這個第二層級所屬的第一層級 Home元件中,就要寫一層router-view,以此類推
path:'user',
component:User,
}
]
}
]
})
複製程式碼
路由配置生成menu選單
menu其實就是路由的導航,就是router-link,有很多小夥伴會另外建一個叫做menu.js的檔案,然後模擬路由配置的結構去寫一個陣列,然後根據這個檔案遍歷生成dom,是不是有多此一舉的感覺,並且當使用第三方的menu的ui元件時,這種靜態檔案是沒有狀態 (當前訪問路由的對應menu高亮,重新整理頁面或者輸入路由的url進入頁面會丟失高亮) 的。
menu有很多種情況,
- 固定層級,比如固定2層,或者3層,一般後臺管理系統,固定層級較多,因為美觀,整潔。這種就比較方便了。template的dom結構也比較方便。
- “個性”的產品經理,“定製化”的menu選單,未知的層級,這裡就要用到render函式去寫dom。
固定層級
<template>
<div class="menu">
<div class="first-menu" v-for="item,index in menus" :key="item.name">
<router-link :to="item.name">{{ item.meta.zhName }}</router-link>
<template v-if="item.children.length">
<div class="sub-menu" v-for="subItem.subIndex in item.children"
:key="subItem.name">
<img :src="subItem.meta.icon" />
<router-link :to="subItem.name">
{{subItem.meta.zhName}}
</router-link>
</div>
</template>
</div>
</div>
</template>
<script>
export default {
computed:{
menus(){
return this.$router.options.routes
//獲取路由配置
}
}
}
</script>
<style>
.router-link-active{
/* 啟用樣式 */
}
</style>
複製程式碼
這裡我只寫了2層,並且沒有寫樣式,如果使用了像element-ui這樣的menu元件,他底層沒有渲染成router-link
,那就要程式設計式導航了,click
的時候,push
到item.name
,並且當前路由的導航樣式需要根據$route.name(當前路由配置)
來判斷
未知層級
因為不知道是幾層選單,所以在template的html標籤沒辦法自由的遍歷,所以需要js去操作路由配置的遞迴,因為render函式式js操作,所以需要用render函式渲染。
<script>
export default {
computed:{
menus(){
return this.$router.options.routes
//獲取路由配置
}
},
// 使用render函式就不需要寫template標籤的dom了
render(h){
//這個 h 引數,原來的語義是createElement ,這裡使用 h 是方便操作,也是官方建議
// ...... 這裡是操作 menus 的遞迴程式碼,再通過render函式迴圈出來
return h('div','這是一個div')
//這裡必須return 對應的語法
}
}
</script>
複製程式碼
render函式的語法參見官方文件即可 render函式。
這裡有個注意點,如果
router
做了許可權控制,那麼路由配置不能通過$router.options.routes
獲取,因為addRoutes
方法不改變原先的配置,需要在addRoutes
的同時,把完整的路由配置儲存在vuex
,再獲取。許可權控制不細講了,有很多相關文章,但是不建議copy,建議加入自己的理解,沒有絕對的方案。
路由的快取和過渡動畫
過渡動畫應該都用了,一般使用opacity
過渡一下。
<template>
<transition mode="out-in" name="fade">
<!-- 這裡如果在行內直接用$route.meta去v-if判斷快取 dom結構會變複雜 -->
<keep-alive :include="aliveRoutes">
<router-view :key="$route.fullPath" />
<!-- 此處通過路由的完整路徑加上key,當為動態路由時,觸發路由元件重新渲染 -->
</keep-alive>
</transition>
<!-- 都是些官方用法 不細說了-->
</template>
<script>
export default {
computed:{
aliveRoutes(){
// this.$router.options.routes 獲取路由配置
//可以配置meta 是否快取 根據 meta 欄位 push到陣列裡
return [/* ... */]
}
}
}
</script>
複製程式碼
路由的鉤子
官網講的超詳細的。觸發順序也講清楚了,官方的說法叫導航守衛。
注意點:要搞清楚哪些是全域性鉤子,哪些是元件內的鉤子。並且所有的前置鉤子,需要呼叫next() 才會正常進入路由,在寫鉤子函式內部邏輯時,需要注意,不能形成死迴圈
例如
router.beforeEach((to,from,next)=>{
if (from.name === 'login'){
next({
name:'login' //死迴圈
})
//更多next回撥方法可以檢視官方文件
}
})
複製程式碼
元件內鉤子使用情況,要看業務需求,比如動態路由↓↓↓。
動態路由
動態路由,使用場景是一個固定的路由檢視元件,配合一個動態的瀏覽器url,在檢視中顯示不同的資料,同時希望url中有當前詳情的語義,例如詳情頁,使用者資訊頁。
先看下路由如何配置動態,這裡用詳情頁舉例
// router/index.js
const router = new Router({
routes:[
{
path:'/list',
name:'list',
component:List
},
{
path:'/detail/:id',//此處id對應params.id
name:'detail',
component:Detail
}
]
})
複製程式碼
<!-- List.vue -->
<template>
<div>
<ul>
<li @click="goDetail(item.id)" v-for="item in someData" :key="item.id">
</li>
</ul>
</div>
</template>
<script>
export default{
methods:{
goDetail(_id){
this.$router.push({
name:'detail',
//此處注意只有通過name跳轉路由,params才會生效
//query不受影響
params:{
id:_id //此處對應routes配置的/:id
}
})
}
}
}
</script>
複製程式碼
<!-- Detail.vue -->
<script>
export default {
beforeRouteEnter (to, from, next) {
//此處為路由元件內的鉤子,可以通過判斷 to.params.id 是否 undefined,
//進行一些操作,因為即使 to.params.id 是 undefined,路由也能匹配成功
//因為這些id可能是用來獲取資料的,不會在頁面顯示,不一定能察覺是 undefined
}
}
</script>
複製程式碼
關於路由傳參
params
就如上面動態路由所講,只有通過路由配置的name
跳轉,才會生效,即使沒有使用動態路由,也可以通過params
傳參
這裡有注意點:
-
如果使用動態路由,那麼在動態路由頁面重新整理路由,
params
引數依然存在, -
如果沒有使用動態路由,
params
引數只在跳轉路由時有效,重新整理頁面則會丟失params
query
引數,可以通過path
或name
跳轉都可以傳參,並且引數會和ajax
的get
請求一樣,附加到瀏覽器的url上,重新整理頁面依然保留
路由的懶載入
路由元件打包單獨的js,當訪問路由時,載入對應js檔案,加快首頁載入時間,會增加專案的總體積。
npm
或yarn
安裝babel-plugin-syntax-dynamic-import
.babelrc
或babel.config.js
配置
module.exports = {
plugins:["syntax-dynamic-import"]
}
複製程式碼
- 路由檔案使用
// router/index.js
const router = new Router({
routes:[
{
path:'/list',
name:'list',
component:()=>import(/* webpackChunkName:"SOME_NAME" */'path/to/List.vue')
//此處 import 是方法 和 es6 的 import 不一樣
//特殊註釋語法 相同chunkName 打包到一個js中 可省略
}
]
})
複製程式碼
路由的命名檢視
我從來沒用到過命名檢視,不給大家誤導了,我能解釋的就是命名檢視的作用是一個瀏覽器url,匹配多個router-view
。有需求的移步官方文件。
部分api
.vue
檔案中this.$router
是指掛載的路由例項,可以使用push
等方法。.vue
檔案中this.$route
當前路由資訊物件,包括path
,query
等,只讀屬性。router.app
指router
所掛載的vue
例項,可以通過router.app.$options.store
訪問vuex
,前提是main.js
中,要先引入vuex
,後引入router
,否則報錯。router.push()
常用路由跳轉方法,引數為{path?:string,name?:string,params?:object,query?:object}
,需要注意的是,push
為方法名,與陣列沒有聯絡。router.replace()
替換當前路由,引數和push
一致,區別是替換當前路由,即點選瀏覽器的返回,不會回到之前被替換的路由。router.go()
和router.back()
,引數為整數,前進或後退幾步。router.addRoutes()
引數是需要符合routes
配置的資料,動態新增路由配置到原有配置。
結束
有疑問或者講錯的可以提出
tips:懂得分享才能走的更遠。
歡迎來我的Vue技術群交流:887516034
如果覺得對你有用,就打賞一下吧。