在我們做管理后臺亦或是產(chǎn)品流程時扶踊,總是需要一個菜單欄或者導(dǎo)航欄來架起我們的產(chǎn)品架構(gòu)泄鹏,那么,如何用vue實現(xiàn)側(cè)邊折疊導(dǎo)航欄呢姻檀?接下來將一一介紹命满。
請先看效果演示圖。
步驟1:先架構(gòu)整個頁面的布局绣版,撰寫html胶台、css和js
HTML代碼
<template>
<div id="main">
<div class="content">
<!-- 左邊導(dǎo)航欄 -->
<div class="admin_nav col-lg-3 col-xl-2" v-show="fullWidth">
<div class = "admin_nav_site">
<div class="title">
數(shù)據(jù)中心后臺管理
</div>
<ul v-for="(item,index) in navList" :key="index">
<li @click="handleToTitle(index,item)" @mouseenter="changeTitleColor(index)" @mouseleave="removeTitleColor(index)"
ref="title" :class="{active:currentSort == index}" class="col-lg-12">
<div class="left_icon">
<i :class="'iconfont '+item.className"></i>
</div>
<div class="middle">
{{item.title}}
</div>
<div class="right_icon">
<i :class="'iconfont '+item.close"></i>
</div>
</li>
<li v-for="(it,idx) in item.secMenu" :key="idx" v-show="item.isSubShow" class="active1">
<router-link :to="it.path" tag="a">{{it.name}}</router-link>
</li>
</ul>
</div>
</div>
<!-- 右邊內(nèi)容 -->
<div class="admin_content col-12 col-md-12 col-lg-12 col-xl-10">
<div class="admin_header">
<!-- 導(dǎo)航圖標 -->
<div class="H5_item" v-show="!fullWidth">
<i class="iconfont icon-daohanglan" @click="make_menu" class-name="H5-menu"></i>
</div>
<div class="user">
<div class="userHead">
<span>
<img src="../../assets/image/userhead.svg">
</span>
<span>admin</span>
</div>
<div class="logOut">
<i class="iconfont icon-tuichu"></i>
</div>
</div>
</div>
<div class="admin_body">
<keep-alive>
<router-view />
</keep-alive>
</div>
</div>
</div>
</div>
</template>
JS代碼
<script>
import axios from 'axios';
export default {
name: 'navigation',
data() {
return {
navList: [{
title: '用戶管理',
isSubShow: false,
className: 'icon-guanliyuan1',
close: 'icon-close',
up: 'icon-zhedie',
secMenu: [
{
name: '工號管理',
path: '/home/navigation-one/user'
},
// {
// name: '角色管理',
// path: '/home/navigation-one/role'
// },
// {
// name: '權(quán)限管理',
// path: '/home/navigation-one/user'
// },
]
},
{
title: '資源管理',
isSubShow: false,
className: 'icon-ziyuan',
close: 'icon-close',
up: 'icon-zhedie',
secMenu: [
{
name: '我的收藏',
path: '/home/navigation-one/user'
},
{
name: '我的項目',
path: '/home/navigation-one/role'
}
]
},
{
title: '綜合管理',
isSubShow: false,
className: 'icon-zonghe',
close: 'icon-close',
up: 'icon-zhedie',
secMenu: [{
name: '劃配管理',
path: '/home/navigation-one/user'
},
{
name: '數(shù)據(jù)信息',
path: '/home/navigation-one/role'
}
]
},
{
title: '系統(tǒng)消息',
isSubShow: false,
className: 'icon-xiaoxi',
close: 'icon-close',
up: 'icon-zhedie',
secMenu: [{
name: '實時動態(tài)',
path: '/home/navigation-one/user'
},
{
name: '過去動態(tài)',
path: '/home/navigation-one/role'
}
]
}
],
currentSort: 0,
pagetype: "index",
fullWidth: true,
dismenu: true
}
},
methods: {
active(index) {
this.currentSort = index;
},
changeTitleColor(index) {
this.currentSort = index;
},
removeTitleColor(index) {
this.currentSort = null;
},
handleToTitle(ind, item) {
this.navList[ind].isSubShow = !this.navList[ind].isSubShow;
if (this.navList[ind].isSubShow == true) {
this.navList[ind].close = 'icon-zhedie';
} else {
this.navList[ind].close = 'icon-close';
}
}
}
}
</script>
CSS代碼
#main {
background: #F0F6FF;
font-size: 0.16rem;
}
#main .content {
display: flex;
flex-direction: row;
}
.content .admin_nav {
min-height: 9.37rem;
max-height: 1.3rem;
padding: 0 !important;
background: #364150;
position: relative;
}
.content .admin_nav .admin_nav_site{
height: 100vh;
}
.content .admin_nav .title {
height: 1.39rem;
line-height: 1.39rem;
background: rgba(63, 73, 86, 1);
color: #FFFFFF;
text-align: center;
font-size: 0.18rem;
display: flex;
justify-content: center;
}
.content .admin_nav .title div {
padding: 0 0.03rem;
}
.content .admin_nav .title div:first-child i {
font-size: 0.18rem;
}
.content .admin_nav ul .active {
background: rgba(68, 81, 99, 1);
}
.content .admin_nav ul .active1 a.router-link-active {
color: #fff;
}
.content .admin_nav ul li {
height: 0.6rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 0.18rem;
}
.content .admin_nav ul li a {
color: #cecdc5;
cursor: pointer;
}
.content .admin_nav ul li:first-child {
font-size: 0.2rem;
height: 0.64rem;
display: flex;
flex-direction: row;
align-items: center;
color: #BEC5C0;
cursor: pointer;
}
.content .admin_nav ul li:first-child div {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
color: #BEC5C0;
}
.content .admin_nav ul li:first-child .left_icon {
width: 22%;
}
.content .admin_nav ul li:first-child .left_icon i {
color: #1296DB;
}
.content .admin_nav ul li:first-child .middle {
width: 56%;
display: flex;
justify-content: flex-start;
}
.content .admin_nav ul li:first-child .right_icon {
width: 22%;
}
.admin_nav .admin .middle:hover {
color: #fff;
}
.admin_nav .admin .right_icon i:hover {
color: #fff;
}
.admin_nav .admin .middle.router-link-active {
color: #fff;
}
.content .admin_nav_position {
position: absolute;
z-index: 3000;
}
.content .admin_content {
padding: 0 !important;
}
.content .admin_content .admin_header {
width: 100%;
height: 0.6rem;
background: #364150;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.content .admin_content .admin_header .H5_item {
width: 0.4rem;
height: 0.4rem;
border-radius: 0.2rem;
display: flex;
justify-content: center;
align-items: center;
margin-left: 0.2rem;
}
.content .admin_content .admin_header .H5_item i {
font-size: 0.22rem;
color: #fff;
}
.content .admin_content .admin_header .user {
width: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
}
.content .admin_content .admin_header .user .userHead {
height: 0.6rem;
display: flex;
flex-direction: row;
align-items: center;
color: #fff;
font-size: 0.18rem;
}
.content .admin_content .admin_header .user .userHead span {
padding: 0 0.05rem;
}
.content .admin_content .admin_header .user .userHead span:nth-child(1) {
position: relative;
}
.content .admin_content .admin_header .user .userHead span img {
width: 0.4rem;
height: 0.4rem;
border-radius: 50%;
}
.content .admin_content .admin_header .user .userHead span input {
width: 0.4rem;
height: 0.4rem;
position: absolute;
overflow: hidden;
opacity: 0;
cursor: pointer;
}
.content .admin_content .admin_header .user .logOut {
color: #fff;
margin-left: 0.12rem;
margin-right: 0.5rem;
}
.content .admin_content .admin_header .user .logOut i {
color: #1296DB;
font-size: 0.24rem;
cursor: pointer;
}
.toggle-cart-enter-active {
transition: all 0.4s linear;
}
.toggle-cart-leave-active {
transition: all 0.4s linear;
}
.toggle-cart-enter {
transform: translateX(-200%);
}
.toggle-cart-leave-active {
transform: translateX(-200%);
}
步驟2:撰寫完基本網(wǎng)頁布局和樣式后,對部分細節(jié)進行剖析杂抽。
1诈唬、動態(tài)綁定路徑
<router-link :to="it.path" tag="a">{{it.name}}</router-link>
2、一級菜單缩麸,標題及折疊符號
①通過@mouseenter和@mouseleave事件铸磅,當鼠標移入和移出時,改變標題區(qū)域背景顏色
②通過@click事件,當鼠標點擊時阅仔,顯示二級菜單列表
③利用:class動態(tài)綁定類名吹散,觸發(fā)active方法,修改折疊符號狀態(tài)八酒;綁定圖標類名空民,通過遍歷,修改對應(yīng)圖標
<ul v-for="(item,index) in navList" :key="index">
<li @click="handleToTitle(index,item)" @mouseenter="changeTitleColor(index)" @mouseleave="removeTitleColor(index)" ref="title" :class="{active:currentSort == index}" class="col-lg-12">
<div class="left_icon">
<i :class="'iconfont '+item.className"></i>
</div>
<div class="middle">
{{item.title}}
</div>
<div class="right_icon">
<i :class="'iconfont '+item.close"></i>
</div>
</li>
<li v-for="(it,idx) in item.secMenu" :key="idx" v-show="item.isSubShow" class="active1">
<router-link :to="it.path" tag="a">{{it.name}}</router-link>
</li>
</ul>
active(index) {
this.currentSort = index;
},
changeTitleColor(index) {
this.currentSort = index;
},
removeTitleColor(index) {
this.currentSort = null;
},
handleToTitle(ind, item) {
this.navList[ind].isSubShow = !this.navList[ind].isSubShow;
if (this.navList[ind].isSubShow == true) {
this.navList[ind].close = 'icon-zhedie';
} else {
this.navList[ind].close = 'icon-close';
}
}
步驟3:菜單欄完成后羞迷,在網(wǎng)頁端能進行查看界轩,但是還需做一個手機端適配,這樣就達到兩端同步適應(yīng)的效果衔瓮。實現(xiàn)如下:
①對左邊導(dǎo)航欄再撰寫第二套代碼浊猾,并綁定好對應(yīng)的參數(shù)實現(xiàn)顯示和隱藏
②運用vue已有的transition,綁定name值热鞍,實現(xiàn)動畫效果綁定
HTML代碼
<!-- 移動端導(dǎo)航欄 -->
<transition name="toggle-cart">
<div class="admin_nav admin_nav_position col-8 col-md-5 col-lg-3 col-xl-3" v-show="!fullWidth&&!dismenu">
<div class="title">
<div v-show="!fullWidth">
<i class="iconfont icon-daohanglan" @click="make_menu" class-name="H5-menu"></i>
</div>
<div>數(shù)據(jù)中心后臺管理</div>
</div>
<ul v-for="(item,index) in navList" :key="index">
<li @click="handleToTitle(index,item)" @mouseenter="changeTitleColor(index)" @mouseleave="removeTitleColor(index)" ref="title" :class="{active:currentSort == index}">
<div class="left_icon">
<i :class="'iconfont '+item.className"></i>
</div>
<div class="middle">
{{item.title}}
</div>
<div class="right_icon">
<i :class="'iconfont '+item.close"></i>
</div>
</li>
<li v-for="(it,idx) in item.secMenu" :key="idx" v-show="item.isSubShow" class="active1">
<router-link :to="it.path" tag="a">{{it.name}}</router-link>
</li>
</ul>
</div>
</transition>
JS代碼
mounted() {
window.onresize = () => { //監(jiān)聽屏幕變化
this.page_width();
};
this.page_width();
}葫慎,
methods: {
make_menu() { //點擊導(dǎo)航圖標
this.dismenu = !this.dismenu;
},
page_width() { //獲取屏幕寬度
var screenWidth = window.screen.width;
if (screenWidth <= 1024) {
this.fullWidth = false;
} else {
this.fullWidth = true;
}
}
}
最后來看下手機端效果:
附上全文代碼:
<template>
<div id="main">
<div class="content">
<!-- 左邊導(dǎo)航欄 -->
<div class="admin_nav col-lg-3 col-xl-2" v-show="fullWidth">
<div class = "admin_nav_site">
<div class="title">
數(shù)據(jù)中心后臺管理
</div>
<ul v-for="(item,index) in navList" :key="index">
<li @click="handleToTitle(index,item)" @mouseenter="changeTitleColor(index)" @mouseleave="removeTitleColor(index)"
ref="title" :class="{active:currentSort == index}" class="col-lg-12">
<div class="left_icon">
<i :class="'iconfont '+item.className"></i>
</div>
<div class="middle">
{{item.title}}
</div>
<div class="right_icon">
<i :class="'iconfont '+item.close"></i>
</div>
</li>
<li v-for="(it,idx) in item.secMenu" :key="idx" v-show="item.isSubShow" class="active1">
<router-link :to="it.path" tag="a">{{it.name}}</router-link>
</li>
</ul>
</div>
<!-- 管理員端 -->
<!-- <ul class="admin">
<li class="col-lg-12">
<div class="left_icon">
<i class="iconfont icon-guanliyuan1"></i>
</div>
<router-link to="/admin/administrator/secadmin" tag="div" class="middle">管理員端</router-link>
<div class="right_icon">
<i class="iconfont icon-jinru"></i>
</div>
</li>
</ul> -->
</div>
<!-- 右邊內(nèi)容 -->
<div class="admin_content col-12 col-md-12 col-lg-12 col-xl-10">
<div class="admin_header">
<!-- 導(dǎo)航圖標 -->
<div class="H5_item" v-show="!fullWidth">
<i class="iconfont icon-daohanglan" @click="make_menu" class-name="H5-menu"></i>
</div>
<div class="user">
<div class="userHead">
<span>
<img src="../../assets/image/userhead.svg">
</span>
<span>admin</span>
</div>
<div class="logOut">
<i class="iconfont icon-tuichu"></i>
</div>
</div>
</div>
<div class="admin_body">
<keep-alive>
<router-view />
</keep-alive>
</div>
</div>
<!-- 移動端導(dǎo)航欄 -->
<transition name="toggle-cart">
<div class="admin_nav admin_nav_position col-8 col-md-5 col-lg-3 col-xl-3" v-show="!fullWidth&&!dismenu">
<div class="title">
<div v-show="!fullWidth">
<i class="iconfont icon-daohanglan" @click="make_menu" class-name="H5-menu"></i>
</div>
<div>數(shù)據(jù)中心后臺管理</div>
</div>
<ul v-for="(item,index) in navList" :key="index">
<li @click="handleToTitle(index,item)" @mouseenter="changeTitleColor(index)" @mouseleave="removeTitleColor(index)"
ref="title" :class="{active:currentSort == index}">
<div class="left_icon">
<i :class="'iconfont '+item.className"></i>
</div>
<div class="middle">
{{item.title}}
</div>
<div class="right_icon">
<i :class="'iconfont '+item.close"></i>
</div>
</li>
<li v-for="(it,idx) in item.secMenu" :key="idx" v-show="item.isSubShow" class="active1">
<router-link :to="it.path" tag="a">{{it.name}}</router-link>
</li>
</ul>
</div>
</transition>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'navigation-1',
data() {
return {
token: '',
navList: [{
title: '用戶管理',
isSubShow: false,
className: 'icon-guanliyuan1',
close: 'icon-close',
up: 'icon-zhedie',
secMenu: [
{
name: '工號管理',
path: '/home/navigation-one/user'
},
// {
// name: '角色管理',
// path: '/home/navigation-one/role'
// },
// {
// name: '權(quán)限管理',
// path: '/home/navigation-one/user'
// },
]
},
{
title: '資源管理',
isSubShow: false,
className: 'icon-ziyuan',
close: 'icon-close',
up: 'icon-zhedie',
secMenu: [
{
name: '我的收藏',
path: '/home/navigation-one/user'
},
{
name: '我的項目',
path: '/home/navigation-one/role'
}
]
},
{
title: '綜合管理',
isSubShow: false,
className: 'icon-zonghe',
close: 'icon-close',
up: 'icon-zhedie',
secMenu: [{
name: '劃配管理',
path: '/home/navigation-one/user'
},
{
name: '數(shù)據(jù)信息',
path: '/home/navigation-one/role'
}
]
},
{
title: '系統(tǒng)消息',
isSubShow: false,
className: 'icon-xiaoxi',
close: 'icon-close',
up: 'icon-zhedie',
secMenu: [{
name: '實時動態(tài)',
path: '/home/navigation-one/user'
},
{
name: '過去動態(tài)',
path: '/home/navigation-one/role'
}
]
}
],
currentSort: 0,
pagetype: "index",
fullWidth: true,
dismenu: true
}
},
mounted() {
window.onresize = () => { //監(jiān)聽屏幕變化
this.page_width();
};
this.page_width();
},
methods: {
active(index) {
this.currentSort = index;
},
changeTitleColor(index) {
this.currentSort = index;
},
removeTitleColor(index) {
this.currentSort = null;
},
handleToTitle(ind, item) {
this.navList[ind].isSubShow = !this.navList[ind].isSubShow;
if (this.navList[ind].isSubShow == true) {
this.navList[ind].close = 'icon-zhedie';
} else {
this.navList[ind].close = 'icon-close';
}
},
make_menu() { //點擊導(dǎo)航圖標
this.dismenu = !this.dismenu;
},
page_width() { //獲取屏幕寬度
var screenWidth = window.screen.width;
if (screenWidth <= 1024) {
this.fullWidth = false;
} else {
this.fullWidth = true;
}
}
}
}
</script>
<style scoped>
#main {
background: #F0F6FF;
font-size: 0.16rem;
}
#main .content {
display: flex;
flex-direction: row;
}
.content .admin_nav {
min-height: 9.37rem;
max-height: 1.3rem;
padding: 0 !important;
background: #364150;
position: relative;
}
.content .admin_nav .admin_nav_site{
height: 100vh;
}
.content .admin_nav .title {
height: 1.39rem;
line-height: 1.39rem;
background: rgba(63, 73, 86, 1);
color: #FFFFFF;
text-align: center;
font-size: 0.18rem;
display: flex;
justify-content: center;
}
.content .admin_nav .title div {
padding: 0 0.03rem;
}
.content .admin_nav .title div:first-child i {
font-size: 0.18rem;
}
.content .admin_nav ul .active {
background: rgba(68, 81, 99, 1);
}
.content .admin_nav ul .active1 a.router-link-active {
color: #fff;
}
.content .admin_nav ul li {
height: 0.6rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 0.18rem;
}
.content .admin_nav ul li a {
color: #cecdc5;
cursor: pointer;
}
.content .admin_nav ul li:first-child {
font-size: 0.2rem;
height: 0.64rem;
display: flex;
flex-direction: row;
align-items: center;
color: #BEC5C0;
cursor: pointer;
}
.content .admin_nav ul li:first-child div {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
color: #BEC5C0;
}
.content .admin_nav ul li:first-child .left_icon {
width: 22%;
}
.content .admin_nav ul li:first-child .left_icon i {
color: #1296DB;
}
.content .admin_nav ul li:first-child .middle {
width: 56%;
display: flex;
justify-content: flex-start;
}
.content .admin_nav ul li:first-child .right_icon {
width: 22%;
}
.admin_nav .admin .middle:hover {
color: #fff;
}
.admin_nav .admin .right_icon i:hover {
color: #fff;
}
.admin_nav .admin .middle.router-link-active {
color: #fff;
}
.content .admin_nav_position {
position: absolute;
z-index: 3000;
}
.content .admin_content {
padding: 0 !important;
}
.content .admin_content .admin_header {
width: 100%;
height: 0.6rem;
background: #364150;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.content .admin_content .admin_header .H5_item {
width: 0.4rem;
height: 0.4rem;
border-radius: 0.2rem;
display: flex;
justify-content: center;
align-items: center;
margin-left: 0.2rem;
}
.content .admin_content .admin_header .H5_item i {
font-size: 0.22rem;
color: #fff;
}
.content .admin_content .admin_header .user {
width: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
}
.content .admin_content .admin_header .user .userHead {
height: 0.6rem;
display: flex;
flex-direction: row;
align-items: center;
color: #fff;
font-size: 0.18rem;
}
.content .admin_content .admin_header .user .userHead span {
padding: 0 0.05rem;
}
.content .admin_content .admin_header .user .userHead span:nth-child(1) {
position: relative;
}
.content .admin_content .admin_header .user .userHead span img {
width: 0.4rem;
height: 0.4rem;
border-radius: 50%;
}
.content .admin_content .admin_header .user .userHead span input {
width: 0.4rem;
height: 0.4rem;
position: absolute;
overflow: hidden;
opacity: 0;
cursor: pointer;
}
.content .admin_content .admin_header .user .logOut {
color: #fff;
margin-left: 0.12rem;
margin-right: 0.5rem;
}
.content .admin_content .admin_header .user .logOut i {
color: #1296DB;
font-size: 0.24rem;
cursor: pointer;
}
.toggle-cart-enter-active {
transition: all 0.4s linear;
}
.toggle-cart-leave-active {
transition: all 0.4s linear;
}
.toggle-cart-enter {
transform: translateX(-200%);
}
.toggle-cart-leave-active {
transform: translateX(-200%);
}
</style>
注:
1、css樣式中的rem換算成px為對應(yīng)的rem值*100,如:font-size:0.24rem薇宠;=> font-size:24px幅疼;
2、文章中涉及到的iconfont類名是因為引用了阿里圖標昼接,如遇到不知道如何引用的可以翻閱博文→ https://blog.csdn.net/weixin_44803753/article/details/113423633
3爽篷、關(guān)于router-link對應(yīng)的跳轉(zhuǎn),如有小伙伴不太清楚如何使用vue-router配置路由的可以翻閱博文→https://blog.csdn.net/weixin_44803753/article/details/113436625
Ending(〃'▽'〃)慢睡!