最近接受的新案子bug有点多,天天在忙着修改bug,导致更新有点慢了。。。
抽空写了个响应式的导航,个人觉得功能比较完善,有兴趣的可以一起探讨本导航主要实现了以下功能:
1.自适应浏览器窗口大小,支持pc、pad、phone等设备web浏览
2.导航栏顶部与侧边自动切换,768以下屏幕自动显示侧边导航,以上则显示顶部导航
3.本导航支持主菜单+子菜单
4.搜索样式切换,可以点击搜索展开/收起搜索框,当屏幕小于450时隐藏点击搜索时隐藏logo图案,收起时恢复。
等等功能吧,废话不多说,先来看看效果展示吧:
创建模板
还是老样式,我们先把模板搭起来,这里需要注意的事我们的菜单列表这里我写了两套,一套适应于pc端,一个适用于mobile。可能有人会说代码冗余了,所以这里我们用 的是v-if和v-else来判断的,当listShow为真时使用pc这段代码,当listShow为假时使用mobile这段代码。这里我侧边菜单用了transition过渡,如果你觉得顶部有需要可以自行添加。
<template> <div class="navMenu"> <div class="navArea"> <div class="logo"> <div class="menuIcon"> <i class=" iconfont icon-daohang" @click="sideMenu"></i> </div> <div class="logoImg" v-show="logopPic"> <img :src="logo" alt=""> </div> </div> <ul v-if="listShow" class="menuList"> <li class="first" v-for="(menu,id) in menuData" :key="id" @click="menuShow(menu,id)" :class="{fisrtMenu:menu.bigshowclass}"> <i :class="menu.icon"></i>{{menu.title}} <transition name="pc_fade"> <ul class="menuChild" v-show="menu.isSubShow"> <li class="second" v-for="(child,index) in menu.childs" :key="index" @click="pushpath(child,menu,index)" :class="{secondMenu:child.showclass}"> <i :class="child.icon"></i>{{child.title}} </li> </ul> </transition> </li> </ul> <transition name="mobileMenu" v-else> <ul class="mobile" v-show="sideList"> <li class="first" v-for="(menu,id) in menuData" :key="id" @click="menuShow(menu,id)" :class="{fisrtMenu:menu.bigshowclass}"> <i :class="menu.icon"></i>{{menu.title}} <transition name="mobile_fade"> <ul class="mobileChild" v-show="menu.isSubShow"> <li class="second" v-for="(child,index) in menu.childs" :key="index" @click="pushpath(child,menu,index)" :class="{secondMenu:child.showclass}"> <i :class="child.icon"></i>{{child.title}} </li> </ul> </transition> </li> <div class="weChat"> <p>欢迎关注微信公众号:</p> <img :src="weiImg" alt="weixin"> </div> </ul> </transition> <div class="search" :class="{inputStyle:searchInput}" > <input type="text" placeholder="请输入关键字进行搜索" v-model="keyWord" v-show="searchInput" > <i class="iconfont icon-search" @click="search"></i> </div> </div> </div> </template>
CSS样式编写
上次写分页的时候发现样式还是挺多的,这里就不全部附上了,把关键的提取过来吧,毕竟样式对于前端来说都是so easy的,这里主要是侧边菜单的过渡效果和自适应的调整,部分写在样式里面了。实现原理在dom中定义了transition过渡,定义一个name属性,设置的过渡样式fade-enter-active和fade-leave-active分别指定了载入和离开时的动作。
.mobileMenu-enter-active { transition: all .8s ease; } .mobileMenu-leave-active { transition: all .5s cubic-bezier(1.0, 0.5, 0.8, 1.0); } .mobileMenu-enter, .mobileMenu-leave-to{ transform: translateX(-20px); opacity: 0; } .mobile_fade-enter-active{ transition: all 1s ease; } .mobile_fade-leave-active { transition: all 0s cubic-bezier(1.0, 0.5, 0.8, 1.0); } .mobile_fade-enter, .mobile_fade-leave-to{ transform: translateY(); opacity: 0; } @media screen and (min-width: 769px){ .logo .menuIcon i{ display: none; } } @media screen and (max-width: 769px){ .logo{ flex:1; } } @media screen and (max-width: 850px){ .menuList .first{ padding:0 5px; } } @media screen and (max-width: 1200px){ .menuList .first i{ display: none; } }
功能逻辑实现
功能一:自适应屏幕菜单切换,这就要我们时刻来监听浏览器宽度了,这里我们可以使用window.addEventListener来实现监听,获取document.documentElement.clientWidth或document.body.clientWidth即为屏幕显示的宽度,拿到这个宽度我们做些判断,改变listShow、searchInput、logopPic的属性来实现自动适应屏幕样式。
mounted(){ window.addEventListener('resize', this.Switching) }, methods: { Switching(){ let that = this let w = document.documentElement.clientWidth || document.body.clientWidth if(w >= 769){ that.listShow = true; //显示pc菜单 } if(w <769){ that.listShow = false; //显示mobile菜单 } if(w<450){ that.searchInput=false //隐藏input框 that.logopPic=true //显示logo that.sideList=false //隐藏侧边栏 }else{ that.sideList=true //显示侧边栏 } if(w>1000){ that.searchInput=true //显示input框 }else{ that.searchInput=false //隐藏input框 } }, }
功能二:搜索功能,当点击搜索图标时,判断input是否显示切有无值,如果有的话就执行搜索操作,这里我们忽略了路由请求操作,需要的自行添加,如果没有值则用来切换input状态,隐藏和现实input框,当屏幕小于450时因为宽度不够,显示时我将logo给隐藏了,隐藏时再次显示logo即可。结合前面的屏幕宽度判断,这时input框就可以很好的自适应了。
search(){ if(this.searchInput&&this.keyWord!==''){ let val=this.keyWord }else{ let that = this let w = document.documentElement.clientWidth || document.body.clientWidth if(w < 450){ if(this.logopPic){ this.logopPic=false this.searchInput=!this.searchInput }else{ this.logopPic=true this.searchInput=!this.searchInput } }else{ this.logopPic=true this.searchInput=!this.searchInput } } },
功能三:侧边菜单除了可以根据屏幕宽度来自动隐藏显示,当我们还需要可以手动展开/收起菜单,这里我在左上角留了一个图标,用来提醒用户这里是菜单按钮(小屏幕时自动收起了,pad则自动展开),在图标上添加点击事件@click="sideMenu"。
sideMenu(){ this.sideList=!this.sideList },
功能四:最主要的菜单点击功能,点击一级菜单时改变样式,如果有二级菜单则显示二级菜单,再次点击则收起子菜单。选择二级菜单时同样改变对应样式,这样用户就可以很清楚的知道自己当前正处于哪个菜单项中了。
menuShow(menu,id){ if(menu.isSubShow){ //重置子菜单样式 if(menu.childs){ for(var i = 0;i<menu.childs.length;i++){ menu.childs[i].showclass = false; } } } for(var i = 0;i<this.menuData.length;i++){ //循环改变菜单样式,只保留当前点击的菜单样式 if(i != id){ this.menuData[i].isSubShow = false; } this.menuData[i].bigshowclass = false; this.menuData[id].bigshowclass = true; } menu.isSubShow = !menu.isSubShow //切换子菜单显示效果 },
子菜单同理, 如果没有二级菜单的那么就需要添加路由跳转来实现页面的切换,如子菜单中的this.$router.push(child.path)即可,这里也是把其他子菜单样式清除,保留当前的菜单样式即可。
pushpath(child,menu,index){ this.$router.push(child.path) //路由跳转 let len=menu.childs menu.isSubShow = false; for(var i = 0;i<len.length;i++){ //循环子菜单,关闭其他样式,保留当前菜单样式 len[i].showclass = false; len[index].showclass = true; } } }
菜单数据结构
到这里基本都功能实现了,下面我们看看菜单列表是什么结构吧,这里我们把当前点击的样式状态写在了列表中,当对应的bigshowclass和showclass为真时样式生效,我们就是通过控制这些属性来实现样式的清除和添加的。
menuData: [ { title:"一级菜单", icon: "el-icon-message", // path:'', classShow: true, bigshowclass:false, isSubShow:false, }, { icon: "el-icon-message", title: "两级菜单", bigshowclass:false, isSubShow:false, childs:[ { icon: "el-icon-loading", title: "权限管理", path:'', showclass:false, }, { icon: "el-icon-bell", title: "角色管理", path:'', showclass:false, } ] }, { icon: "el-icon-news", title: "三级菜单", bigshowclass:false, isSubShow:false, }, { icon: "el-icon-news", title: "四级菜单", isSubShow:false, bigshowclass:false, childs: [ { icon: "el-icon-phone-outline\r\n", title: "帐号管理", path:'', showclass:false, }, { icon: "el-icon-picture", title: "积分管理", path:'', showclass:false, } ] }, { icon: "el-icon-news", title: "五级菜单", bigshowclass:false, isSubShow:false, }, { icon: "el-icon-news", title: "六级菜单", bigshowclass:false, isSubShow:false, }, ],
这就是今天分享的内容了,下面是mobile端的效果。有不懂的可以留言,也欢迎指正!
欢迎关注本人的公众号:编程手札,文章也会在公众号更新
本文暂时没有评论,来添加一个吧(●'◡'●)