詳解使用vuex進(jìn)行菜單管理
vuex 的優(yōu)勢(shì)在復(fù)雜狀態(tài)管理中才能提現(xiàn)出來(lái)。
如果項(xiàng)目中有多級(jí)菜單,且不同組件中散布多個(gè)相同級(jí)別的菜單,項(xiàng)目同一時(shí)刻各級(jí)菜單有且僅有一個(gè)高亮,菜單跳轉(zhuǎn)時(shí)除了路由改變,相應(yīng)菜單也要高亮(之前的恢復(fù)非高亮狀態(tài)),這便是個(gè)使用 vuex 再好不過(guò)的場(chǎng)景。
使用 DOM 操作進(jìn)行簡(jiǎn)單菜單管理
使用 DOM 進(jìn)行菜單管理,背后的思想是:在點(diǎn)擊菜單的同時(shí),將事件對(duì)象傳入事件處理程序,想讓當(dāng)前高亮的 menu 非高亮,再讓點(diǎn)擊的 menu 高亮。
<div class="menu-url"> <span class="active userList" @click="menuClicked($event, 'userList')">注冊(cè)</span> <span class="chargeList" @click="menuClicked($event, 'chargeList')">充值</span> <span class="buyList" @click="menuClicked($event, 'buyList')">購(gòu)買</span> <span class="bangList" @click="menuClicked($event, 'bangList')">到期</span> <span class="withDrawList" @click="menuClicked($event, 'withDrawList')">提現(xiàn)</span> </div>
menuClicked (event, url) { // 當(dāng)前高亮的 menu 非高亮 const currentActiveLink = this.querySelector('.active'); currentActiveLink.classList.remove('active'); // 當(dāng)前點(diǎn)擊的 menu 高亮 event.target.classList.add('active'); // 路由跳轉(zhuǎn) this.$router.push(`/panel/list/${url}`); },
這樣雖然實(shí)現(xiàn)了點(diǎn)擊切換時(shí) menu 高亮,但有一個(gè) bug:每次初始化都會(huì)使默認(rèn)的 menu 變成高亮,如果此時(shí)在非默認(rèn)高亮的 menu 中用戶手動(dòng)刷新頁(yè)面,會(huì)導(dǎo)致 menu 高亮錯(cuò)誤(比如在 buylist 頁(yè)面刷新頁(yè)面后,頁(yè)面內(nèi)容依然停留在 buylist,但高亮的菜單卻變成了 userlist)。
如果要解決這個(gè) bug,就需要在本地存儲(chǔ)(刷新不改變存儲(chǔ)狀態(tài)) menu 狀態(tài),本地存儲(chǔ)可以選擇不同的方案,在此不做討論,但可以肯定的是 DOM + 本地存儲(chǔ)控制 menu 高亮的方案在項(xiàng)目逐漸變大以后會(huì)變得難以維護(hù)。
現(xiàn)在是 vuex 登場(chǎng)的時(shí)候了。
使用 vuex 進(jìn)行菜單管理
使用 vuex 進(jìn)行菜單管理需要 在開發(fā)前就規(guī)劃好菜單的層級(jí)
,以便在 vuex 分配 state
和 mutations
。
規(guī)劃層級(jí)
確定項(xiàng)目中哪些是一級(jí)菜單,哪些是二級(jí)菜單,以此類推…… 這里要注意的是,為簡(jiǎn)化操作,同級(jí)別菜單都以不同名稱命名,這樣在 vuex 中就不需要關(guān)注菜單屬于那個(gè)頁(yè)面,只關(guān)注狀態(tài)就好。菜單層級(jí)通常如下:
|-root | | | |-first-menu1 | | |- second-menu1 | | |- second-menu2 | | |- second-menu3 | | | |-first-menu2 | |- second-menu3 | |- second-menu4 | |- second-menu5
在 vuex 分配 `state` 和 `mutations`
不同層級(jí)的菜單分別占用一個(gè) `state`,至于 `mutations`,本例中不同 `state` 分別對(duì)應(yīng)寫了一個(gè) `mutations`,實(shí)際工作中為了更大成都減少代碼復(fù)用,對(duì)于 menu 的狀態(tài)管理可以只寫一個(gè) `mutations`,通過(guò)傳參判斷是更改哪個(gè)層級(jí)及對(duì)應(yīng)的 menu。
需要注意的是 vuex 在頁(yè)面刷新后狀態(tài)會(huì)重新初始化,這顯然和管理菜單所需功能不符(除了主動(dòng)觸發(fā),其他操作不能對(duì)菜單產(chǎn)生影響)??梢酝ㄟ^(guò)vuex-persistedstate 改變 vuex 默認(rèn)生命周期,下面示例代碼將 vuex 狀態(tài)存儲(chǔ)在了 cookie 中:
js
const store = new Vuex.Store({ state: { // 初始化 activeFirstMenu: 'firstMenu1', activeSecondMenu : 'secondMenu1', }, mutations: { // 更改一級(jí)菜單 changeFirstActiveMenu (state, menu) { state.activeFirstMenu = menu; }, // 更改二級(jí)二級(jí)菜單 changeSecondActiveMenu (state, menu) { state.activeSecondMenu = menu; } }, });
組件中渲染
在 template 動(dòng)態(tài)加載高亮 class,通過(guò) vuex 中 state 控制:
<div class="subMenu"> <span :class="{ activeSecondMenu: activeMenu.secondMenu1 }" @click="menuClicked('secondMenu1')">secondMenu1</span> </div> <div class="subMenu"> <span :class="{ activeSecondMenu: activeMenu.secondMenu2 }" @click="menuClicked('secondMenu2')">secondMenu2</span> </div> <div class="subMenu"> <span :class="{ activeSecondMenu: activeMenu.secondMenu3 }" @click="menuClicked('secondMenu3')">secondMenu3</span> </div>
寫 js 時(shí)有個(gè)技巧:路由 path 和對(duì)應(yīng)高亮的 menu 名稱最好相同,因?yàn)槁酚商D(zhuǎn)和高亮 menu 直接相關(guān),這樣可以減少一個(gè)參數(shù):
data () { return { // 初始化 activeMenu: { // menu 名稱相同,和對(duì)應(yīng)路由的 path 相同 secondMenu1: '', secondMenu2: '', secondMenu3: '', }, }; }, computed: { activeMenuName () { // 檢測(cè) vuex 中 activeSecondMenu 的變化 return this.$store.state.activeSecondMenu; } }, methods: { menuClicked(path) { // 取消當(dāng)前 tab 高亮 this.activeMenu[this.activeMenuName] = false; // 更新 vuex 狀態(tài)及 menu 高亮 this.$store.commit("changeSecondActiveMenu", path); this.activeMenu[this.activeMenuName] = true; // 路由跳轉(zhuǎn) path 和對(duì)應(yīng) menu 名稱相同 this.$router.push(`/somePath/${path}`); }, init () { // 刷新頁(yè)面重置正確高亮菜單tab this.activeMenu[this.activeMenuName] = true; }, }, mounted: { this.init(); },
其他
對(duì)于 vuex 的優(yōu)化
上文有談到,實(shí)際工作中為了更大程度實(shí)現(xiàn)代碼復(fù)用,對(duì)于某個(gè)類別的狀態(tài)管理可以只寫一個(gè) mutations ,通過(guò)傳參(Payload )判斷更改內(nèi)容。還是以 menu 管理為例,可進(jìn)行下面的優(yōu)化:
vuex 優(yōu)化后如下:
const store = new Vuex.Store({ // 其他代碼略 mutations: { // 優(yōu)化后代碼,合并 changeFirstActiveMenu 和 changeSecondActiveMenu changeActiveMenu (state, menuInfo) { state[menuInfo.menuHierarchy] = menuInfo.name; } } });
組件 js 部分優(yōu)化后如下:
methods: { menuClicked(path) { // 其他代碼略高亮 // 優(yōu)化后代碼:更改一級(jí)和二級(jí)菜單觸發(fā)同個(gè) mutation this.$store.commit("changeActiveMenu", { menuHierarchy: 'activeFirstMenu', name: path, }); this.$store.commit("changeActiveMenu", { menuHierarchy: 'activeSecondMenu', name: path, }); // 其他代碼略 }, },
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
解決vue 退出動(dòng)畫無(wú)效的問(wèn)題
這篇文章主要介紹了解決vue 退出動(dòng)畫無(wú)效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08Vue-cli 如何將px轉(zhuǎn)化為rem適配移動(dòng)端
這篇文章主要介紹了Vue-cli 如何將px轉(zhuǎn)化為rem適配移動(dòng)端,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-07-07解決keep-alive同一個(gè)組件不緩存問(wèn)題
這篇文章給大家介紹了如何解決keep-alive同一個(gè)組件不緩存問(wèn)題,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-02-02利用Vue.js實(shí)現(xiàn)checkbox的全選反選效果
最近用vue做了兩個(gè)項(xiàng)目,都需要實(shí)現(xiàn)全選反選的功能,所以想著記錄下分享給大家,方便自己或者有需要的朋友們參考講學(xué)習(xí),所以下面這篇文章主要介紹了利用Vue.js實(shí)現(xiàn)checkbox的全選反選效果,需要的朋友可以一起來(lái)學(xué)習(xí)學(xué)習(xí)。2017-01-01vuejs數(shù)據(jù)超出單行顯示更多,點(diǎn)擊展開剩余數(shù)據(jù)實(shí)例
這篇文章主要介紹了vuejs數(shù)據(jù)超出單行顯示更多,點(diǎn)擊展開剩余數(shù)據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05使用vue ant design分頁(yè)以及表格分頁(yè)改為中文問(wèn)題
這篇文章主要介紹了使用vue ant design分頁(yè)以及表格分頁(yè)改為中文問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。2023-04-04