應用el-tabs模擬nav menu元件
目前在做的專案遇到如圖所示需求。 本是個簡單的menu, 但是我偏選了el-tabs元件為基礎進行改寫,花了好多時間,也踩了不少坑。但總算是完成啦!特此記錄填坑記錄。
routerMap結構為簡單的二維陣列,根據需求,最多二維,不考慮更深的巢狀及外鏈情況;
路由詳情請參考路由配置項及示例。
註冊元件Navbar
這就不說了。。
應用router資料生成el-tabs
獲取router資料
computed: { routes() { return this.$router.options.routes } } 複製程式碼
渲染el-tabs,將非隱藏的router展示出來
<el-tabs v-model="activeName" @tab-click="handleClick"> <el-tab-pane v-for="route in routes" class="slideInUp" v-if="!route.hidden&&route.children" :name="route.path" :label= "route.name" > </el-tab-pane> </el-tabs> 複製程式碼
說到這還沒什麼難得,接下來問題來了。
問題一:動態渲染 label
為 icon+text
label
作為 el-tab-pane
的屬性接收的是字串,但是我要的label,不僅要文字,還要在上面加上我的 icon
. 折騰許久無果後無奈只好給element報了個 ofollow,noindex">feature 。終於在此找到了思路: label slot
.
<div slot="label"> <svg-icon class="icons" :icon-class="iconClassName(route)" /> <span class="nav-title">{{route.name}}</span> </div> 複製程式碼
在 el-tab-pane
中間填上 slot
,我的icon們果然乖乖出現了! 開森!
sub-menu生成
因為用的 el-tab
做 navbar
,submenu生成將 router.children
放到 el-tab-pane之間即可
問題二:動態渲染active class
根據需求,點選submenu後顏色就要發生變化,正好應用一下動態繫結class:
<li v-for="(item, key, index) in route.children" :key="item.name" :id = "index" style="cursor: pointer;" :class="{'sub-active':activeIndex == item.path}" @click="activeIndex = item.path, clickLink(item, $event)"> {{item.name}} </li> 複製程式碼
根據path的唯一性,點選時 activeIndex
更改為當前的 path
,當前 submenu
會新增上 activeIndex
類.
問題三:點選submenu路由更改
導航的重要作用就是控制路有更改,應用 path.resolve
可以生成當前點選的路徑。 li
中新增的 clickLink
方法為:
const path = this.resolvePath(routePath) this.$router.push(path) 複製程式碼
resolvePath
為:
resolvePath(routePath) { return path.resolve(this.basePath, routePath) } 複製程式碼
因為 this.$router.push
可以實現路由跳轉,但是當前的跳轉路徑只解析出了子目錄;
更正方案: 在 el-tab-pane
新增 :index="resolvePath(route.path)"
,在最初渲染時獲取相應的父級path。 之後二級路由就變成了: http://localhost:9528/#/task/index
,嗯,是哀家想要的樣子~
基本的功能以為就這樣實現了,知道我手動輸入了一下路徑,,,
根據輸入的path更新tab中對應項
active tab
由資料 activeName
控制; 子選單 activeIndex
項繫結的是各自的 path
.
失敗嘗試一:
新增watch,監控router變化更改 activeName
以及 activeIndex
,未果;
失敗嘗試二:
應用 mixins
生成區域性鉤子函式,覆蓋 activeName
以及 activeIndex
,未果;
失敗原因: 應用路由鉤子的思路是對的,但必須全域性守衛,然後發現路由變化時更新 activeName
以及 activeIndex
對應的值,這時候再用 store
獲取新值進行覆蓋。
問題四:手動輸入的路徑渲染menu
- store中新增menu
const menu = { state: { menumain: '/', menusub:'overview' }, mutations: { updatemain (state,n) { state.menumain = n }, updatesub (state,n) { state.menusub = n } } } export default menu 複製程式碼
新增守衛函式:
router.beforeEach((to, from, next) => { // add menu change data let paths = to.path.trim().split('/') let activeName ='' let activeIndex ='' activeName = !!paths[2]==true ? '/'+ paths[1] : '/' store.commit('updatemain', activeName) activeIndex = !!paths[2]==true ? paths[2] : paths[1] store.commit('updatesub', activeIndex) //end menu }) 複製程式碼
navbar中更新資料:
computed: { newActiveName() { return this.$store.getters.menumain; }, newActiveSubMenu() { return this.$store.getters.menusub; } }, watch: { newActiveName(val){ this.activeName = val }, newActiveSubMenu(val) { this.activeIndex = val } } 複製程式碼
通過計算屬性發現path更改並獲取新值,然後watch監測到資料變化將新值賦給 activeName
以及 activeIndex
。
看下結果吧!

,有意向的也可直接加我微信諮詢。
忙到半夜總算實現了,開始以為很難,做的很慢,每次搞定一個小點又覺得很容易。還是“難者不會,會者不難”吧。
另:vue中很多設計都會有意想不到的用處,比如這次用到的插槽,動態繫結class;回想當年勇jq遍歷li刪掉active再給某一項新增active class的日子還歷歷在目。資料驅動解放dom操作,yeah~