详解使用vuex进行菜单管理


Posted in Javascript onDecember 21, 2017

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

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

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

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

<div 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>
</div>
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 控制:

<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 时有个技巧:路由 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,
  });

  // 其他代码略
 },
},

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
7个Javascript地图脚本整理
Oct 20 Javascript
JavaScript高级程序设计(第3版)学习笔记11 内建js对象
Oct 11 Javascript
jQuery中is()方法用法实例
Jan 06 Javascript
jQuery实现跟随鼠标运动图层效果的方法
Feb 02 Javascript
使用JS中的exec()方法构造正则表达式验证
Aug 01 Javascript
利用JS提交表单的几种方法和验证(必看篇)
Sep 17 Javascript
JavaScript拖动层Div代码
Mar 01 Javascript
angularjs指令之绑定策略(@、=、&amp;)
Apr 13 Javascript
angular bootstrap timepicker TypeError提示怎么办
Jun 13 Javascript
ajax前台后台跨域请求处理方式
Feb 08 Javascript
jQuery.validate.js表单验证插件的使用代码详解
Oct 22 jQuery
解决VUE双向绑定失效的问题
Oct 29 Javascript
Angular5.1新功能分享
Dec 21 #Javascript
vue2中的keep-alive使用总结及注意事项
Dec 21 #Javascript
webpack写jquery插件的环境配置
Dec 21 #jQuery
基于Vue 2.0的模块化前端 UI 组件库小结
Dec 21 #Javascript
使用Bootstrap4 + Vue2实现分页查询的示例代码
Dec 21 #Javascript
详解设置Webstorm 利用babel将ES6自动转码成ES5
Dec 20 #Javascript
代码详解Vuejs响应式原理
Dec 20 #Javascript
You might like
php设计模式 Builder(建造者模式)
2011/06/26 PHP
PHP隐形一句话后门,和ThinkPHP框架加密码程序(base64_decode)
2011/11/02 PHP
php FLEA中二叉树数组的遍历输出
2012/09/26 PHP
php中JSON的使用与转换
2015/01/14 PHP
php备份数据库类分享
2015/04/14 PHP
PHP随机生成唯一HASH值自定义函数
2015/04/20 PHP
php数组冒泡排序算法实例
2016/05/06 PHP
js内存泄露的几种情况详细探讨
2013/05/31 Javascript
浅析Node.js中使用依赖注入的相关问题及解决方法
2015/06/24 Javascript
JavaScript模块化开发之SeaJS
2015/12/13 Javascript
微信小程序 图片等比例缩放(图片自适应屏幕)
2016/11/16 Javascript
JavaScript数据结构与算法之二叉树添加/删除节点操作示例
2019/03/01 Javascript
Vue源码探究之虚拟节点的实现
2019/04/17 Javascript
微信小程序实现下拉框功能
2019/07/16 Javascript
vux-scroller实现移动端上拉加载功能过程解析
2019/10/08 Javascript
vscode+gulp轻松开发小程序的完整步骤
2020/10/18 Javascript
夯基础之手撕javascript继承详解
2020/11/09 Javascript
[36:37]2014 DOTA2华西杯精英邀请赛5 24 VG VS iG
2014/05/25 DOTA
kNN算法python实现和简单数字识别的方法
2014/11/18 Python
Ubuntu下使用Python实现游戏制作中的切分图片功能
2018/03/30 Python
Python 实现输入任意多个数,并计算其平均值的例子
2019/07/16 Python
Python 在局部变量域中执行代码
2020/08/07 Python
用CSS3打造HTML5的Logo(实现代码)
2016/06/16 HTML / CSS
一个基于canvas的移动端图片编辑器的实现
2020/10/28 HTML / CSS
英国最受欢迎的价格比较网站之一:MoneySuperMarket
2018/12/19 全球购物
应用艺术专业个人的自我评价
2014/01/03 职场文书
大学班长的职责
2014/01/27 职场文书
员工合理化建议书
2014/05/19 职场文书
幼儿园五一劳动节活动总结
2015/02/09 职场文书
病人慰问信范文
2015/02/15 职场文书
2015教师节师德演讲稿
2015/03/19 职场文书
开学季:喜迎新生,迎新标语少不了
2019/11/07 职场文书
mysql5.6主从搭建以及不同步问题详解
2021/12/04 MySQL
剑指Offer之Java算法习题精讲二叉树的构造和遍历
2022/03/21 Java/Android
MySQL批量更新不同表中的数据
2022/05/11 MySQL
mysql sock文件存储了什么信息
2022/07/15 MySQL