详解使用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 相关文章推荐
JavaScript异步调用定时方法并停止该方法实现代码
Mar 16 Javascript
自动最大化窗口的Javascript代码
May 22 Javascript
JavaScript常用脚本汇总(二)
Mar 04 Javascript
jquery通过closest选择器修改上级元素的方法
Mar 17 Javascript
JavaScript中的Math.atan2()方法使用详解
Jun 15 Javascript
JavaScript用select实现日期控件
Jul 17 Javascript
js+css绘制颜色动态变化的圈中圈效果
Jan 27 Javascript
Angular.js与Bootstrap相结合实现表格分页代码
Apr 12 Javascript
MUI实现上拉加载和下拉刷新效果
Jun 30 Javascript
vue2.0 常用的 UI 库实例讲解
Dec 12 Javascript
原生js+ajax分页组件
Jan 30 Javascript
vue-cli+webpack项目打包到服务器后,ttf字体找不到的解决操作
Aug 28 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提取字符串中的图片地址[正则表达式]
2011/11/12 PHP
PHP扩展CURL的用法详解
2014/06/20 PHP
PHP面向对象程序设计组合模式与装饰模式详解
2016/12/02 PHP
laravel框架邮箱认证实现方法详解
2019/11/22 PHP
javascript实现的鼠标链接提示效果生成器代码
2007/06/28 Javascript
比较简单的异步加载JS文件的代码
2009/07/18 Javascript
基于jQuery的获得各种控件Value的方法
2010/11/19 Javascript
jquery.bgiframe.js在IE9下提示INVALID_CHARACTER_ERR错误
2013/01/11 Javascript
javascript中this做事件参数相关问题解答
2013/03/17 Javascript
浅析js中2个等号与3个等号的区别
2013/08/06 Javascript
js之事件冒泡和事件捕获详细介绍
2013/10/28 Javascript
判断js中各种数据的类型方法之typeof与0bject.prototype.toString讲解
2013/11/07 Javascript
javascript结合CSS实现苹果开关按钮特效
2015/04/07 Javascript
利用jQuery实现WordPress中@的ID悬浮显示评论内容
2015/12/11 Javascript
jquery ztree实现模糊搜索功能
2016/02/25 Javascript
由简入繁实现Jquery树状结构的方法(推荐)
2016/06/10 Javascript
AngularJS之依赖注入模拟实现
2016/08/19 Javascript
微信小程序使用第三方库Underscore.js步骤详解
2016/09/27 Javascript
JS中substring与substr的用法
2016/11/16 Javascript
使用nodejs下载风景壁纸
2017/02/05 NodeJs
ejsExcel模板在Vue.js项目中的实际运用
2018/01/27 Javascript
读懂CommonJS的模块加载
2019/04/19 Javascript
解决在layer.open中使用时间控件laydate失败的问题
2019/09/11 Javascript
使用webpack将ES6转化ES5的实现方法
2019/10/13 Javascript
Electron 打包问题:electron-builder 下载各种依赖出错(推荐)
2020/07/09 Javascript
解决vue+router路由跳转不起作用的一项原因
2020/07/19 Javascript
Vue+Element UI 树形控件整合下拉功能菜单(tree + dropdown +input)
2020/08/28 Javascript
python表格存取的方法
2018/03/07 Python
学习python可以干什么
2019/02/26 Python
python GUI库图形界面开发之PyQt5信号与槽事件处理机制详细介绍与实例解析
2020/03/08 Python
建议书怎么写
2014/03/12 职场文书
教师节活动总结
2014/08/29 职场文书
2014年医院党建工作总结
2014/12/20 职场文书
大学生逃课检讨书
2015/05/04 职场文书
Nginx配置https的实现
2021/11/27 Servers
详解TypeScript的基础类型
2022/02/18 Javascript