文章目录
参考视频:
案例 | 链接 |
---|---|
【前端】Vue+Element UI案例:定制设计定制设计定制设计定制设计定制设计定制设计定制设计定制设计定制设计定制设计通用后台管理系统-导航栏(视频p1-16) | |
【前端】Vue+Element UI案例:通用后台管理系统-Header+定制设计导航栏折叠(p17-19) | |
【前端】Vue+Element UI案例:通用后台管理系统-Home组件:卡片、表格(p20-22) | |
【前端】Vue+Element UI案例:通用后台管理系统-Echarts图表准备:axios封装、mock定制设计数据模拟实战(p23-25) | |
【前端】Vue+Element UI案例:通用后台管理系统-Echarts图表:折线图、柱状图、饼状图(p27-30) | |
【前端】Vue+Element UI案例:通用后台管理系统-面包屑、tag栏(p31-35) | |
【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Form表单填写、Dialog定制设计对话框弹出(p36-38) | |
【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Table定制设计表格增删查改、Pagination分页、搜索框(p39-42) | |
【前端】Vue+Element UI案例:通用后台管理系统-登陆页面Login(p44) | |
【前端】Vue+Element UI案例:通用后台管理系统-定制设计登陆页面功能:登录权限跳转、路由守卫、退出(p45-46) | |
【前端】Vue+Element UI案例:通用后台管理系统-登陆不同用户显示不同菜单、动态添加路由(p47-48) | |
【前端】Vue+Element UI案例:通用后台管理系统-项目总结 |
目标
- 悬停效果
- 点击效果
- 其他:点击展开和收缩
- 动态显示“首页”“商品管理”等
- 有路由跳转
其实是项目的导航栏组件。只打算看导航栏部分的可以跳过1.其他准备。
代码
0.数据
我们把它单独放到一个MenuData.js中,然后用export default
暴露出来。
{ path: '/', name: 'home', label: '首页', icon: 's-home', url: 'Home/Home' }, { path: '/mall', name: 'mall', label: '商品管理', icon: 'video-play', url: 'MallManage/MallManage' }, { path: '/user', name: 'user', label: '用户管理', icon: 'user', url: 'UserManage/UserManage' }, { label: '其他', icon: 'location', children: [ { path: '/page1', name: 'page1', label: '页面1', icon: 'setting', url: 'Other/PageOne' }, { path: '/page2', name: 'page2', label: '页面2', icon: 'setting', url: 'Other/PageTwo' } ] }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
1.其他准备
注意要查看官方文档:
全局引入Element UI
先安装Element UI:
npm i element-ui -S
- 1
全局引入:在main.js中
import ElementUI from 'element-ui'Vue.use(ElementUI)
- 1
- 2
- 3
路由配置
这里我们先配置Home页面(会显示导航栏的页面)。官方文档:
安装:这里的版本是3.6.5
ps:可以在网站上查到包的所有版本,我们这里要的是3.x.x的最新版。
npm install vue-router@3.6.5
- 1
路由的配置:目前只配置了Main组件的
import Vue from "vue";import VueRouter from "vue-router";import Main from '../Views/Main'Vue.use(VueRouter)const routes=[ // 主路由 { path:'/', component:Main }]const router = new VueRouter({ routes})export default router
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
目前的依赖
当前的package.json文件的dependencies应当如下:
"dependencies": { "core-js": "^3.8.3", "element-ui": "^2.15.10", "vue": "^2.6.14", "vue-router": "^3.6.5" }
- 1
- 2
- 3
- 4
- 5
- 6
当前的main.js
import Vue from 'vue'import App from './App.vue'import ElementUI from 'element-ui'import 'element-ui/lib/theme-chalk/index.css';import router from './router/index'Vue.config.productionTip = falseVue.use(ElementUI)new Vue({ router, render: h => h(App),}).$mount('#app')
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
Main.vue布局结构
要的是这个布局:
找到对应代码:
<el-container> <el-aside width="200px">Aside</el-aside> <el-container> <el-header>Header</el-header> <el-main>Main</el-main> </el-container></el-container>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
把它放到Main.vue里。
App.vue如下:
<template> <div id="app"> <router-view></router-view> </div></template><script>export default {}</script><style></style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
效果:
接下来我们写一个组件:CommonAside.vue,把导航栏写在这个组件里,再把组件放到Aside中。
因此放了布局的Main.vue如下:
<template> <el-container> <el-aside width="200px"> <common-aside/> </el-aside> <el-container> <el-header>Header</el-header> <el-main>Main</el-main> </el-container> </el-container></template><script>import CommonAside from '../components/CommonAside.vue'export default { data(){ return{} }, components:{ CommonAside }}</script><style></style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
组件CommonAside如下:
<template> <!-- 在这里开始写导航栏 --></template><script>export default {}</script><style></style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
接下来就是本文正题:导航栏。
2.结构
我们现在Element UI官方文档上找到类似的导航结构:就是你了!
阅读代码,我们不难发现代码分为“展开收起”部分和“导航”部分,我们要的是导航部分。把代码对着我们的目标稍作调整得到:
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" :collapse="isCollapse"> <el-menu-item index="2"> <i class="el-icon-menu"></i> <span slot="title">导航一</span> </el-menu-item> <el-submenu index="1"> <template slot="title"> <i class="el-icon-location"></i> <span slot="title">导航二</span> </template> <el-menu-item-group> <span slot="title">分组一</span> <el-menu-item index="1-1">选项1</el-menu-item> <el-menu-item index="1-2">选项2</el-menu-item> </el-menu-item-group> </el-submenu></el-menu>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
效果:
3.动态显示数据
导航栏分为一级导航栏和二级导航栏,目标中的 其他-页面1 就是二级导航栏,首页、商品管理、用户管理 都是一级导航栏。
一级和二级的区别在于:数据中是否有children属性,如果有,那它的children属性就是二级导航。所以这里要用到计算属性。
computed:{ noChildren(){ // 如果没有children则返回true,会被过滤器留下 return this.MenuData.filter(item=>!item.children) }, hasChildren(){ return this.MenuData.filter(item=>item.children) }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
一级导航栏的循环显示:
<!-- 观察数据,我们发现name是唯一标识 --><!-- 查看文档,index是唯一标识 --> <el-menu-item v-for="item in noChildren" :key="item.name" :index="item.name"> <!-- 这里是字体图标,用模板字符串拼接,注意要动态绑定 --> <i :class="`el-icon-${item.icon}`"></i> <span slot="title">{{item.label}}</span> </el-menu-item>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
效果:
二级导航栏也是类似做法:
<el-submenu v-for="item in hasChildren" :key="item.name" :index="item.name"> <template slot="title"> <i :class="`el-icon-${item.icon}`"></i> <span slot="title">{{item.label}}</span> </template> <el-menu-item-group v-for="subItem in item.children" :key="subItem.name"> <el-menu-item :index="subItem.name">{{subItem.label}}</el-menu-item> </el-menu-item-group> </el-submenu></el-menu>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
效果:
4.主题:背景色,点击悬停效果
再次打开文档,找到自定义颜色部分:
显然是这里:我们把它直接复制粘贴。
则标签如下:
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose":collapse="isCollapse" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b">
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
效果:就是这样!
5.去除padding
在浏览器中F12可知,padding是由body等标签自动带有的,我们只需要在App.vue中把它们清除即可(reset)。
html,body,h3,p { margin: 0; padding: 0}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
6.去除下拉框
这里我们先:这样写CSS可以嵌套,更加方便。
npm install less less-loader --save
- 1
浏览器F12,显然有下拉框的这个类是:el-menu
把el-menu设置成height:100vh即可。
7.标题
html:
<!-- 要放到导航栏里面 --><h3>通用后台管理系统</h3>
- 1
- 2
css:
<style lang="less" scoped>.el-menu{ height:100vh; h3{ text-align: center; line-height: 48px; color: #fff; font-size: 16px; font-weight: 400; }}</style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
效果:
8.路由跳转
添加点击事件:
<el-menu-item @click="clickItem(item)" v-for="item in noChildren" :key="item.name" :index="item.name">
- 1
- 2
- 3
- 4
- 5
<el-menu-item-group v-for="subItem in item.children" :key="subItem.name"> <el-menu-item @click="clickItem(subItem)" :index="subItem.name">{{ subItem.label }}</el-menu-item></el-menu-item-group>
- 1
- 2
- 3
js:
clickItem(item){ // 防止自己跳自己的报错 if(this.$route.path!==item.path&&!(this.$route.path==='/home'&&(item.path==='/'))){ this.$router.push(item.path) }}
- 1
- 2
- 3
- 4
- 5
- 6
不过目前只有一个路由。
总代码
组件CommonAside.vue
<template> <el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" :collapse="isCollapse" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b"> <!-- 要放到导航栏里面 --> <h3>通用后台管理系统</h3> <!-- 观察数据,我们发现name是唯一标识 --> <!-- 查看文档,index是唯一标识 --> <el-menu-item @click="clickItem(item)" v-for="item in noChildren" :key="item.name" :index="item.name"> <!-- 这里是字体图标,用模板字符串拼接,注意要动态绑定 --> <i :class="`el-icon-${item.icon}`"></i> <span slot="title">{{ item.label }}</span> </el-menu-item> <el-submenu v-for="item in hasChildren" :key="item.name" :index="item.name"> <template slot="title"> <i :class="`el-icon-${item.icon}`"></i> <span slot="title">{{ item.label }}</span> </template> <el-menu-item-group @click="clickItem(subItem)" v-for="subItem in item.children" :key="subItem.name"> <el-menu-item :index="subItem.name">{{ subItem.label }}</el-menu-item> </el-menu-item-group> </el-submenu> </el-menu></template><style lang="less" scoped>.el-menu-vertical-demo:not(.el-menu--collapse) { width: 200px; min-height: 400px;}.el-menu{ height:100vh; h3{ text-align: center; line-height: 48px; color: #fff; font-size: 16px; font-weight: 400; }}</style><script>import MenuData from '../data/MenuData'export default { data() { return { isCollapse: false, MenuData }; }, methods: { handleOpen(key, keyPath) { console.log(key, keyPath); }, handleClose(key, keyPath) { console.log(key, keyPath); }, clickItem(item){ // 防止自己跳自己的报错 if(this.$route.path!==item.path&&!(this.$route.path==='/home'&&(item.path==='/'))){ this.$router.push(item.path) } } }, computed: { noChildren() { // 如果没有children则返回true,会被过滤器留下 return this.MenuData.filter(item => !item.children) }, hasChildren() { return this.MenuData.filter(item => item.children) } }}</script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77