最近接受的新案子bug有点多,天天在忙着修改bug,导致更新有点慢了。。。

抽空写了个响应式的导航,个人觉得功能比较完善,有兴趣的可以一起探讨本导航主要实现了以下功能:

1.自适应浏览器窗口大小,支持pc、pad、phone等设备web浏览

2.导航栏顶部与侧边自动切换,768以下屏幕自动显示侧边导航,以上则显示顶部导航

3.本导航支持主菜单+子菜单

4.搜索样式切换,可以点击搜索展开/收起搜索框,当屏幕小于450时隐藏点击搜索时隐藏logo图案,收起时恢复。

等等功能吧,废话不多说,先来看看效果展示吧:

element UI 响应式布局容器_ico

创建模板

还是老样式,我们先把模板搭起来,这里需要注意的事我们的菜单列表这里我写了两套,一套适应于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端的效果。有不懂的可以留言,也欢迎指正!