计算机系统应用教程网站

网站首页 > 技术文章 正文

Vue实战029:功能完善的响应式导航设计详解

btikc 2024-09-05 12:47:12 技术文章 12 ℃ 0 评论

最近接受的新案子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端的效果。有不懂的可以留言,也欢迎指正!

欢迎关注本人的公众号:编程手札,文章也会在公众号更新

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表