记一次Vue跨导航栏问题解决方案
简述
这篇文章是我项目中,遇到的一个issue,我将解决过程和方法记录下来。
本篇文章基于Vue.js进行的前端页面构建,由于仅涉及前端,将不做数据来源及其他部分的叙述。使用的CSS框架是 BootstrapVue 和 Element-UI 。数据使用 json 文件进行模拟,数据可在文章末的链接源码中查看
需求描述
项目需求是实现双导航栏:顶部导航栏和侧边导航栏。顶部导航栏用于展示一级菜单,根据点击的不同一级菜单,在屏幕左侧展示不同的二级三级导航栏。要求当前页面导航栏菜单需要高亮。
需求分析
数据,json 文件使用axios进行获取,然后赋值给Home.vue下的menus变量,再分发到Nav.vue中,进行一级导航的展示。默认情况下,高亮第一个一级菜单。如果该一级菜单下没有二级菜单和三级菜单,则不显示左侧导航栏,如果有,则展示。当点击了一级菜单时,默认页面展示该菜单下的第一个菜单的页面。
例如:点击了第一个菜单,这个菜单有二级,三级菜单,则展示该菜单下的三级菜单的页面,如果没有三级菜单,则展示二级菜单的页面,如果没有二级菜单,则展示一级菜单的页面。
默认情况下,渲染完成侧边导航栏后高亮导航栏的第一个最下级菜单
主要代码结构
遇到的问题
1、父组件与子组件相互传值
父组件传值给子组件(Home.vue,父):
父组件传值个子组件(myNav.vue,子)
子组件通过props进行数据的接收,该属性是一个数组的形式,父组件通过绑定的形式直接给组件的属性赋值便可实现父组件向子组件传值。
子组件传值给父组件(myNav.vue 子):
子组件传值给父组件(Home.vue 父):
父组件传值给子组件与子组件传值给父组件不同,父组件需要对自定义事件进行监听,而子组件需要触发该事件才能够通过$emit进行传值,在父组件中,传值的接收变量名固定为$event,不能使用其他名字进行获取数据。
2、顶部导航栏的高亮问题
因为顶部导航栏使用的是Bootstrap-Vue框架,所以高亮菜单时只需加上class:active便可以使其高亮,问题是根据需求,高亮的控制权交由父组件Home.vue,而不在子组件myNav.vue中完成,这也就涉及到了刚刚说的组件传值的问题,上述已经叙述过组件传值的问题,此处仅简述其逻辑。
子组件中绑定点击事件后,会将点击的一级菜单的ID值传给父组件。由于原需求中,可能会涉及到URL跳转到任意页面,所以,根据this.$route.path来判断是哪一个页面,再将这个页面的ID值传回给子组件。
传回后使用三元运算符,来比对是否与渲染时id匹配,若匹配,则高亮
3、左侧导航的高亮问题
需求重述:
点击一级菜单,若该菜单数据中存在二级菜单,则在左侧导航栏中显示,如不存在,则隐藏左侧导航栏。默认情况下,若该一级菜单有下属三级子菜单,则跳转第一个下属二级子菜单下的第一个下属三级菜单;若没有三级菜单,则跳转第一个下属二级子菜单的URL;若没有下属二级子菜单,则跳转至一级的URL。在此基础上,高亮当前的菜单。
与顶部导航栏不同,顶部导航栏的高亮是依靠菜单的点击和路由来控制,而侧边导航栏使用的是element-UI的导航栏,根据default-active进行高亮。
default-active的原理是该属性的值与菜单中的index进行比较,若相等则高亮。原理很简单,但是实现起来却没有那么容易。
第一次解决方案:在点击一级菜单时,上述已经说过,将id值传给父组件Home.vue中。父组件监听到该事件触发后,遍历之前通过axios获取到的数据,最终找到匹配的一级菜单,进而判断该菜单下是否有二级乃至三级菜单,若有,则显示第一个,并且将该属性的url值赋值给上述的default-active。
从原理的角度来说,该思想没有问题。可是该方法会导致一个问题,在进入页面后,点击任何一级菜单都能够正常生效,但是互相点击时,左侧导航不显示高亮,页面能够正常跳转。
例如:进入到该页面后,第一次点击任何一级菜单都没有问题,正常显示。在第二次点击任何菜单时均没有高亮显示。
在模拟数据中,有一个一级菜单没有下属菜单,若第一次点击除此菜单以外的菜单时,均可正常显示。第二次若点击除此菜单以外的菜单时,并不会高亮。
我想说的是,若第二次点击的是这个没有下属菜单的一级菜单,第三次再去点任意菜单,又可以正常显示了。
对于这个问题,至少在我看来觉得是很神奇的。于是我将这个操作模拟到每一次的页面点击中,也就是任何一次点击都做一次向那个没有数据的菜单来一次跳转,再跳转回来,发现问题解决了。
那么问题出现在哪里,应该怎样解决,总不至于,每次跳转都需要经过那个没有下属菜单的页面吧,数据是动态的,并不清楚哪个一级菜单没有下属页面菜单。
分析
跳转至无下属菜单的一级菜单时,做了两件事,1:将侧边导航栏数据清空,2:隐藏侧边导航栏。
跳转至其他菜单时,也做了两件事,1:重新赋值侧边导航栏,2:显示侧边导航栏。
首先排除隐藏/显示导航栏,样式的修改,应该不至于会出现这种问题。(其实我也偷偷试过。。)
接下来就只剩下赋值和清空数据了
该代码如下
click1thMenu (id) {
this.menus2th = []
this.active1thMenu = id
for (let i = 0; i < this.menus.length; i++) {
if (this.menus[i].id === id) {
if (this.menus[i].child !== undefined) {
this.asideWidth = '200px'
this.menus2th = this.menus[i].child
} else {
this.asideWidth = '0'
}
}
}
}
我的代码逻辑中,不管是赋值还是情况操作都会将数据清空。到这里,问题就扑朔迷离了。
好了,不卖关子了,直接说结果
我思考,会不会因为在有下属菜单的情况下,清空语句执行后再执行赋值语句,会导致情况语句成为无用代码,被浏览器直接优化掉了,于是我在赋值语句上加了一个延时函数,给他一定的延时。
methods: {
click1thMenu (id) {
this.menus2th = []
this.active1thMenu = id
for (let i = 0; i < this.menus.length; i++) {
if (this.menus[i].id === id) {
if (this.menus[i].child !== undefined) {
this.asideWidth = '200px'
setTimeout(() => {
this.menus2th = this.menus[i].child
}, 10)
} else {
this.asideWidth = '0'
}
}
}
}
然后发现问题就解决了,如果有明白这个原理的大神,也欢迎在下面留言讨论
源码地址:https://gitee.com/handsky/vue-nav
记一次Vue跨导航栏问题解决方案的更多相关文章
- 超详细Vue实现导航栏绑定内容锚点+滚动动画+vue-router(hash模式可用)
超详细Vue实现导航栏绑定内容锚点+滚动动画+vue-router(hash模式可用) 转载自:https://www.jianshu.com/p/2ad8c8b5bf75 亲测有效~ <tem ...
- 使用vue给导航栏添加链接
如下面的导航栏,使用vue技术给该导航栏增加链接: js代码为: navigation:function(){ new Vue({ el: '#navUl', data: { menuData:{ ' ...
- Nuxt/Vue自定义导航栏Topbar+标签栏Tabbar组件
基于Vue.js实现自定义Topbar+Tabbar组件|仿咸鱼底部凸起导航 最近一直在倒腾Nuxt项目,由于Nuxt.js是基于Vue.js的服务端渲染框架,只要是会vue,基本能很快上手了. 一般 ...
- Vue设置导航栏为公共模块并在登录页不显示
1.公共模块的内容可以放在App.vue中但是通常登录页面是不需要导航的,那么就需要规避登录页这时,就可以采用keep-alive结合$route.meta来实现这个功能.keep-alive 是 V ...
- vue 侧边导航栏递归显示
import axios from "axios"; import tabs1 from "../tab_content/tab1.vue"; import m ...
- vue组件导航栏动态添加class
- 用Vue来实现音乐播放器(五):路由配置+顶部导航栏组件开发
路由配置 在router文件夹下的index.js中配置路由 import Vue from 'vue' import Router from 'vue-router'//配置路由前先引入组件impo ...
- ElementUI+命名视图实现复杂顶部和左侧导航栏
在了解了命名视图的用途后,发现用命名视图来实现复杂导航更加省力.更多知识请参考这里 这里只说明重要配置内容,其他内容配置请参考上一篇初始版本: ElementUI 复杂顶部和左侧导航栏实现 或参考文末 ...
- 使用vue封装一个tab栏切换的左侧导航栏的公共组件
首先看最终效果图: 1.compent文件夹里添加tab文件夹,里面创建index.vue index.js index.css index.vue内的template部份代码如下:(最新更正:代码 ...
随机推荐
- 使用有道云笔记还是github写笔记的优缺点对比
有道云笔记的优点 在手机上编辑笔记,有道云的体验更好,建议:新建普通类型笔记而不是markdown笔记,因为md在手机上的编辑体验并不好 插入图片方便无需考虑图床 可以把笔记分享到社交平台(QQ,微信 ...
- 【NX二次开发】Block UI 指定点
属性说明 属性 类型 描述 常规 BlockID String 控件ID Enable Logical 是否可操作 Group ...
- Perm 排列计数
题目描述 称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案可能很 ...
- 【模拟7.25】回家(tarjan V-DCC点双连通分量的求法及缩点 求割点)模板题
作为一道板子题放在第二题令人身心愉悦,不到一个小时码完连对拍都没打. 关于tarjan割点的注意事项: 1.在该板子中我们求的是V-DCC,而不是缩点,V-DCC最少有两个点组成,表示出掉一个块里的任 ...
- Python常用数据结构(列表)
Python中常用的数据结构有序列(如列表,元组,字符串),映射(如字典)以及集合(set),是主要的三类容器 内容 序列的基本概念 列表的概念和用法 元组的概念和用法 字典的概念和用法 各类型之间的 ...
- SQL Prompt快捷键
1. DF DELETE FROM 2. ssf SELECT * FROM 3. be BEGIN END 4. ij INNER JOIN 5. ap ALTER PROCEDURE 6 ...
- Vue.js的基础学习
Vue.js的基础网上很多,这里不记录 开始正式页面的开发 1.页面加载时请求数据 methods: { post() { //发送post请求 this.$http.post('../../ashx ...
- MySQL—Dos命令操作数据库
MySQL 是一个关系型数据库,存在表的概念 结构,数据库可以存放多张表,每个表可以存放多个字段,每个字段可以存放多个记录 Dos命令操作数据库 PhpStudy使用终端打开数据库 第一次打开默认的密 ...
- Redis之复制
1.配置 1.1 建立复制 参与复制的Redis实例划分为主节点(master) 和从节点(slave).默认情况下,Redis都是主节点.每个从节点只能有一个主节点,而主节点可以同时具有多个从节点. ...
- 66.QT-线程并发、QTcpServer并发、QThreadPool线程池
1.线程并发一个程序内部能拥有多个线程并行执行.一个线程的执行可以被认为是一个CPU在执行该程序.当一个程序运行在多线程下,就好像有多个CPU在同时执行该程序.总之,多线程即可以这么理解:多线程是处理 ...