视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
如何使用vuex实现菜单管理
2020-11-27 19:36:29 责编:小采
文档


本篇文章主要介绍了详解使用vuex进行菜单管理,现在分享给大家,也给大家做个参考。

vuex 的优势在复杂状态管理中才能提现出来。

如果项目中有多级菜单,且不同组件中散布多个相同级别的菜单,项目同一时刻各级菜单有且仅有一个高亮,菜单跳转时除了路由改变,相应菜单也要高亮(之前的恢复非高亮状态),这便是个使用 vuex 再好不过的场景。

使用 DOM 操作进行简单菜单管理

使用 DOM 进行菜单管理,背后的思想是:在点击菜单的同时,将事件对象传入事件处理程序,想让当前高亮的 menu 非高亮,再让点击的 menu 高亮。

<p class="menu-url">
 <span class="active userList" @click="menuClicked($event, 'userList')">注册</span>
 <span class="chargeList" @click="menuClicked($event, 'chargeList')">充值</span>
 <span class="buyList" @click="menuClicked($event, 'buyList')">购买</span>
 <span class="bangList" @click="menuClicked($event, 'bangList')">到期</span>
 <span class="withDrawList" @click="menuClicked($event, 'withDrawList')">提现</span>
</p>
menuClicked (event, url) {
 // 当前高亮的 menu 非高亮
 const currentActiveLink = this.querySelector('.active');
 currentActiveLink.classList.remove('active');
 // 当前点击的 menu 高亮
 event.target.classList.add('active');
 // 路由跳转
 this.$router.push(`/panel/list/${url}`);
},

这样虽然实现了点击切换时 menu 高亮,但有一个 bug:每次初始化都会使默认的 menu 变成高亮,如果此时在非默认高亮的 menu 中用户手动刷新页面,会导致 menu 高亮错误(比如在 buylist 页面刷新页面后,页面内容依然停留在 buylist,但高亮的菜单却变成了 userlist)。

如果要解决这个 bug,就需要在本地存储(刷新不改变存储状态) menu 状态,本地存储可以选择不同的方案,在此不做讨论,但可以肯定的是 DOM + 本地存储控制 menu 高亮的方案在项目逐渐变大以后会变得难以维护。

现在是 vuex 登场的时候了。

使用 vuex 进行菜单管理

使用 vuex 进行菜单管理需要 在开发前就规划好菜单的层级 ,以便在 vuex 分配 state mutations

规划层级

确定项目中哪些是一级菜单,哪些是二级菜单,以此类推…… 这里要注意的是,为简化操作,同级别菜单都以不同名称命名,这样在 vuex 中就不需要关注菜单属于那个页面,只关注状态就好。菜单层级通常如下:

|-root
| |
| |-first-menu1
| | |- second-menu1
| | |- second-menu2
| | |- second-menu3
| |
| |-first-menu2
| |- second-menu3
| |- second-menu4
| |- second-menu5

在 vuex 分配 `state` 和 `mutations`

不同层级的菜单分别占用一个 `state`,至于 `mutations`,本例中不同 `state` 分别对应写了一个 `mutations`,实际工作中为了更大成都减少代码复用,对于 menu 的状态管理可以只写一个 `mutations`,通过传参判断是更改哪个层级及对应的 menu。

需要注意的是 vuex 在页面刷新后状态会重新初始化,这显然和管理菜单所需功能不符(除了主动触发,其他操作不能对菜单产生影响)。可以通过vuex-persistedstate 改变 vuex 默认生命周期,下面示例代码将 vuex 状态存储在了 cookie 中:

js

const store = new Vuex.Store({
 state: {
 // 初始化
 activeFirstMenu: 'firstMenu1',
 activeSecondMenu : 'secondMenu1',
 },
 mutations: {
 // 更改一级菜单
 changeFirstActiveMenu (state, menu) {
 state.activeFirstMenu = menu;
 },
 // 更改二级二级菜单
 changeSecondActiveMenu (state, menu) {
 state.activeSecondMenu = menu;
 }
 },
});

组件中渲染

在 template 动态加载高亮 class,通过 vuex 中 state 控制:

<p class="subMenu">
 <span :class="{ activeSecondMenu: activeMenu.secondMenu1 }" @click="menuClicked('secondMenu1')">secondMenu1</span>
</p>
<p class="subMenu">
 <span :class="{ activeSecondMenu: activeMenu.secondMenu2 }" @click="menuClicked('secondMenu2')">secondMenu2</span>
</p>
<p class="subMenu">
 <span :class="{ activeSecondMenu: activeMenu.secondMenu3 }" @click="menuClicked('secondMenu3')">secondMenu3</span>
</p>

写 js 时有个技巧:路由 path 和对应高亮的 menu 名称最好相同,因为路由跳转和高亮 menu 直接相关,这样可以减少一个参数:

data () {
 return {
 // 初始化
 activeMenu: {
 // menu 名称相同,和对应路由的 path 相同
 secondMenu1: '',
 secondMenu2: '',
 secondMenu3: '',
 },
 };
},
computed: {
 activeMenuName () {
 // 检测 vuex 中 activeSecondMenu 的变化
 return this.$store.state.activeSecondMenu;
 }
},
methods: {
 menuClicked(path) {
 // 取消当前 tab 高亮
 this.activeMenu[this.activeMenuName] = false;

 // 更新 vuex 状态及 menu 高亮
 this.$store.commit("changeSecondActiveMenu", path);
 this.activeMenu[this.activeMenuName] = true;

 // 路由跳转 path 和对应 menu 名称相同 
 this.$router.push(`/somePath/${path}`);
 },
 init () {
 // 刷新页面重置正确高亮菜单tab
 this.activeMenu[this.activeMenuName] = true;
 },
},
mounted: {
 this.init();
},

其他

对于 vuex 的优化

上文有谈到,实际工作中为了更大程度实现代码复用,对于某个类别的状态管理可以只写一个 mutations ,通过传参(Payload )判断更改内容。还是以 menu 管理为例,可进行下面的优化:

vuex 优化后如下:

const store = new Vuex.Store({
 // 其他代码略

 mutations: {
 // 优化后代码,合并 changeFirstActiveMenu 和 changeSecondActiveMenu
 changeActiveMenu (state, menuInfo) {
 state[menuInfo.menuHierarchy] = menuInfo.name;
 }
 }
});

组件 js 部分优化后如下:

methods: {
 menuClicked(path) {
 // 其他代码略高亮

 // 优化后代码:更改一级和二级菜单触发同个 mutation
 this.$store.commit("changeActiveMenu", {
 menuHierarchy: 'activeFirstMenu',
 name: path,
 });

 this.$store.commit("changeActiveMenu", {
 menuHierarchy: 'activeSecondMenu',
 name: path,
 });

 // 其他代码略
 },
},

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

使用React如何防止出现重复渲染

使用vue如何实现grid-layout功能

详细介绍在Bootstrap中为Modal添加拖拽功能

在JS中如何实现预览效果

使用three.js制作一个项目

下载本文
显示全文
专题