详解使用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 相关文章推荐
textarea不能通过maxlength属性来限制字数的解决方法
Sep 01 Javascript
jQuery中:animated选择器用法实例
Dec 29 Javascript
js实现鼠标滑过文字链接色彩变化的效果
May 06 Javascript
js判断手机访问或者PC的几个例子(常用于手机跳转)
Dec 15 Javascript
CSS3 3D 技术手把手教你玩转
Sep 02 Javascript
javascript中setAttribute兼容性用法分析
Dec 12 Javascript
Angular2-primeNG文件上传模块FileUpload使用详解
Jan 14 Javascript
详解微信小程序Radio选中样式切换
Jul 06 Javascript
react-native中ListView组件点击跳转的方法示例
Sep 30 Javascript
electron 安装,调试,打包的具体使用
Nov 06 Javascript
Vue项目页面跳转时浏览器窗口上方显示进度条功能
Mar 26 Javascript
基于JS实现视频上传显示进度条
May 12 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
深入掌握include_once与require_once的区别
2013/06/17 PHP
php常用ODBC函数集(详细)
2013/06/24 PHP
PHP实现手机号码中间四位用星号(*)隐藏的自定义函数分享
2014/09/27 PHP
适合PHP初学者阅读的4本经典书籍
2016/09/23 PHP
phpmyadmin下载、安装、配置教程
2017/05/16 PHP
WEB页子窗口(showModalDialog和showModelessDialog)使用说明
2009/10/25 Javascript
JavaScript对象、属性、事件手册集合方便查询
2010/07/04 Javascript
关于firefox的ElementTraversal 接口 使用说明
2010/11/11 Javascript
JS实现的省份级联实例代码
2013/06/24 Javascript
jquery $.fn $.fx是什么意思有什么用
2013/11/04 Javascript
JavaScript实现两个Table固定表头根据页面大小自行调整
2014/01/03 Javascript
JavaScript字符串对象的concat方法实例(用于连接两个或多个字符串)
2014/10/16 Javascript
Javascript验证方法大全
2015/09/21 Javascript
JavaScript函数的调用以及参数传递
2015/10/21 Javascript
jQuery实现右侧显示可向左滑动展示的深色QQ客服效果代码
2015/10/23 Javascript
剖析Node.js异步编程中的回调与代码设计模式
2016/02/16 Javascript
将List对象列表转换成JSON格式的类实现方法
2016/07/04 Javascript
关于微信jssdk实现多图片上传的一点心得分享
2016/12/13 Javascript
jQuery Easyui 下拉树组件combotree
2016/12/16 Javascript
基于vue.js实现侧边菜单栏
2017/03/20 Javascript
Mongoose经常返回e11000 error的原因分析
2017/03/29 Javascript
nodejs批量下载图片的实现方法
2017/05/19 NodeJs
hammer.js实现图片手势放大效果
2017/08/29 Javascript
Vue.js组件间的循环引用方法示例
2017/12/27 Javascript
vue 使用axios 数据请求第三方插件的使用教程详解
2019/07/05 Javascript
vue监听用户输入和点击功能
2019/09/27 Javascript
基python实现多线程网页爬虫
2015/09/06 Python
JavaScript中的模拟事件和自定义事件实例分析
2018/07/27 Python
对Django中的权限和分组管理实例讲解
2019/08/16 Python
QML使用Python的函数过程解析
2019/09/26 Python
python实现画出e指数函数的图像
2019/11/21 Python
Herschel美国官网:背包、手提袋及配件
2020/03/10 全球购物
大学旷课检讨书
2014/01/28 职场文书
大学新闻系求职信
2014/06/03 职场文书
高效笔记技巧分享:学会这些让你不再困扰
2019/09/04 职场文书
MySQL数据库 安全管理
2022/05/06 MySQL