详解使用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 setAttribute, getAttribute 在不同浏览器上的不同表现
Aug 05 Javascript
JS完成代码前最好对其做5件事
Apr 07 Javascript
使用JS取得焦点(focus)元素代码
Mar 22 Javascript
jquery如何扑捉回车键触发的事件
Apr 24 Javascript
使用cluster 将自己的Node服务器扩展为多线程服务器
Nov 10 Javascript
PHP+jQuery+Ajax+Mysql如何实现发表心情功能
Aug 06 Javascript
JS实现微信弹出搜索框 多条件查询功能
Dec 13 Javascript
vue服务端渲染的实例代码
Aug 28 Javascript
JavaScript实现多态和继承的封装操作示例
Aug 20 Javascript
es6函数name属性功能与用法实例分析
Apr 18 Javascript
echarts实现获取datazoom的起始值(包括x轴和y轴)
Jul 20 Javascript
vue实现简单的登录弹出框
Oct 26 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
Apache中php.ini的设置方法
2013/02/28 PHP
Codeigniter(CI)框架分页函数及相关知识
2014/11/03 PHP
深入讲解PHP的Yii框架中的属性(Property)
2016/03/18 PHP
php版微信支付api.mch.weixin.qq.com域名解析慢原因与解决方法
2016/10/12 PHP
解决Extjs4中form表单提交后无法进入success函数问题
2013/11/26 Javascript
JavaScript模拟可展开、拖动与关闭的聊天窗口实例
2015/05/12 Javascript
JavaScript访问字符串中单个字符的两种方法
2015/07/03 Javascript
基于Bootstrap实现tab标签切换效果
2020/04/15 Javascript
Bootstrap精简教程中秋大放送
2016/09/15 Javascript
解决同一页面中两个iframe互相调用jquery,js函数的方法
2016/12/12 Javascript
js/jquery控制页面动态加载数据 滑动滚动条自动加载事件的方法
2017/02/08 Javascript
jQuery插件jquery.kxbdmarquee.js实现无缝滚动效果
2017/02/15 Javascript
解决select2在bootstrap modal中不能正常使用的问题
2018/08/09 Javascript
vue 引用自定义ttf、otf、在线字体的方法
2019/05/09 Javascript
Vue组件通信入门之Provide和Inject机制
2019/12/29 Javascript
JavaScript实现网页计算器功能
2020/10/29 Javascript
如何高效使用Python字典的方法详解
2017/08/31 Python
Python中Threading用法详解
2017/12/27 Python
Python图像的增强处理操作示例【基于ImageEnhance类】
2019/01/03 Python
python 动态生成变量名以及动态获取变量的变量名方法
2019/01/20 Python
Python给图像添加噪声具体操作
2019/03/03 Python
django连接oracle时setting 配置方法
2019/08/29 Python
Python Tensor FLow简单使用方法实例详解
2020/01/14 Python
python实现替换word中的关键文字(使用通配符)
2020/02/13 Python
pandas DataFrame 数据选取,修改,切片的实现
2020/04/24 Python
浅谈Python描述数据结构之KMP篇
2020/09/06 Python
利用Python实现Json序列化库的方法步骤
2020/09/09 Python
Python模拟登录和登录跳转的参考示例
2020/10/30 Python
CSS实现鼠标滑过鼠标点击代码写法
2016/12/26 HTML / CSS
HTML5所有标签汇总及标签意义解释
2015/03/12 HTML / CSS
斯德哥尔摩通票:Stockholm Pass
2018/01/09 全球购物
美国睫毛、眉毛精华液领导品牌:RevitaLash Cosmetics
2018/03/26 全球购物
高中校园广播稿
2014/01/11 职场文书
“学雷锋活动月”总结
2014/03/09 职场文书
浅谈MySQL之select优化方案
2021/08/07 MySQL
Windows server 2022创建创建林、域树、子域的步骤
2022/06/25 Servers