VUE通用后台管理
一、vue-cli4搭建脚手架
1.安装node.js
登录nodejs.cn下载,配置环境变量,配置过程,配置过程2
2.安装cnpm
打开npmmirror.com,在终端运行下面代码
npm install -g cnpm --registry=https://registry.npmmirror.com
运行完成后,输入cnpm -v检验是否安装成功,若cnpm -v无法加载
安装yarn,并检验是否安装成功
3.安装vue-cli脚手架构建工具
cnpm install -g @vue/cli
检验脚手架是否安装成功,vue -V
4.创建项目
vue create vue-manage
选择[Vue 2] babel, eslint,用yarn安装
运行vue run serve
二、引入Element-ui
1.全局引入,并在main.js中引入下面两行
npm i element-ui -S
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
将elementui注入vue,在main.js中写入
Vue.use(ElementUI)
2.打包
npm run build
3.按需引入
npm install babel-plugin-component -D
//借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。
首先,安装 babel-plugin-component
改写mian.js中import ElementUI from 'element-ui';为import {Button} from 'element-ui';
改写Vue.use(ElementUI)为Vue.use(Button)
在babel.config.js中写入
npm i @babel/preset-env -D
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
// ["@babel/preset-env", { "modules": false }] //有问题
],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
三、 vue路由的使用
1.引入vue-router
npm i vue-router@3.2.0
2.在main.js中引入router
new Vue({
router,
render: h => h(App),
}).$mount('#app')
import router from './router'
//import router from '../router'
3.在根目录创建文件夹router,router内创建index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
4.根目录新建views文件夹,内新建Home.vue,User.vue
解决报错:Home报错
<template>
<div>我是Home</div>
</template>
<script>
export default {
data(){
return{}
}
}
</script>
5.在router中index.js
Vue.use(VueRouter)//vuerouter全局引入
import Home from '../views/Home.vue'
import User from '../views/User.vue'
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import User from '../views/User.vue'
Vue.use(VueRouter)//vuerouter全局引入
//1.创建路由组件
//2.将路由与组件进行映射
const routes = [
{path: '/home',component:Home},//首页
{path: '/user',component:User},//用户管理
]
6.定义一个router变量接受router实例
const router = new VueRouter({
mode:'history',//路由匹配模式
routes
})
//配置router
export default router
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import User from '../views/User.vue'
Vue.use(VueRouter)//vuerouter全局引入
//1.创建路由组件
//2.将路由与组件进行映射
const routes = [
{path: '/home',component:Home},//首页
{path: '/user',component:User},//用户管理
]
//3.创建router实例
const router = new VueRouter({
// mode:'history',//路由匹配模式
routes
})
//配置router
export default router
关闭eslint校验:
7.引入router组件,在App.vue(路由出口)
<router-view></router-view>
8.点击不同按钮加载不同路由下的页面,同时进行路由切换(嵌套路由)
在views中新建Main.vue主页面,并在index.js中引入
<template>
<div>
<h1>main</h1>
<router-view></router-view>
</div>
</template>
<script>
export default {
data(){
return{}
}
}
</script>
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import User from '../views/User.vue'
import Main from '../views/Main.vue'
const routes = [
//主路由
{
path:'/',
component:Main,
children:[
//子路由
{path: '/home',component:Home},//首页
{path: '/user',component:User},//用户管理
]
},
]
四、ui搭建
1.首页ui搭建
引用element-ui的container布局(记得在main.js中引入局部element-ui组件)
安装less样式
npm i less
npm i less-loader@5.0.0 --legacy-peer-deps
Main.vue页面
<template>
<div>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-container>
<el-header>Header</el-header>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
export default {
data(){
return{}
}
}
</script>
2.左侧菜单栏的引入
引入element-ui的NavMenu导航菜单,到component中新建CommonAside.vue(侧边栏组件)
在主页Main.vue中引入CommonAside组件
<script>
import CommonAside from '../components/CommonAside.vue'
export default {
data(){
return{}
},
components:{
CommonAside
}
}
</script>
<el-aside width="200px">
<common-aside />
</el-aside>
3.一级菜单的实现
CommonAside组件中实现可展开
return {
isCollapse: false
};
将导航二移到顶部,删除导航三、四
只保留导航二、导航一和导航一下面的选项一
对内容进行渲染,在data的return下加入数据
menuData: [
{
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'
}
]
}
],
过滤数据
computed:{
//没有子菜单
noChildren() {
return this.menuData.filter(item => !item.children)
},
//有子菜单
hasChildren() {
return this.menuData.filter(item => item.children)
}
}
引入icon图标
<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>
noChildren效果图:
4.二级菜单的实现(haschildren)
<el-submenu v-for="item in hasChildren" :key="item.label" :index="item.label">
<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.path">
<el-menu-item :index="subItem.path">{{subItem.label}}</el-menu-item>
</el-menu-item-group>
</el-submenu>
5.菜单样式与less引入
安装less,less-loader
npm i less@4.1.2
npm i less-loader@6.0.0
在component文件下的CommonAside.vue中
<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"
>
引入less部分
<style lang="less" scoped>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
.el-menu{
height: 100vh;
h3 {
color: #fff;
}
}
</style>
<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>
<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>
<el-submenu v-for="item in hasChildren" :key="item.label" :index="item.label">
<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.path">
<el-menu-item :index="subItem.path">{{subItem.label}}</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
</template>
去白边:在App.vue中的style标签
<style lang="less" >
html,body{
margin: 0;
padding: 0
}
</style>
更改<h3>标签中“通用后台管理系统”样式:
在CommonAside.vue中style的h3中
h3{
color: #fff;
text-align: center;
line-height: 48px;
font-size: 16px;
font-weight: 400;
}
在App.vue中的style的html,body中
html,body,h3{
margin: 0;
padding: 0
}
五、菜单点击跳转功能实现(配置路由跳转)
在views中新建Mall.vue,PageOne.vue,PageTwo.vue
在router的index.js中引入
import Mall from '../views/Mall.vue'
import PageOne from '../views/PageOne.vue'
import PageTwo from '../views/PageTwo.vue'
const routes = [
//主路由
{
path:'/',
component:Main,
children:[
//子路由
{path: '/home',component:Home},//首页
{path: '/user',component:User},//用户管理
{path: '/mall',component:Mall},//商品管理
{path: '/page1',component:PageOne},//页面1
{path: '/page2',component:PageTwo},//页面2
]
},
]
实现点击跳转:
添加@click事件
<el-menu-item @click="clickMenu(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>
在methods中加入click事件
//点击菜单
clickMenu(item){
console.log(item)
this.$router.push(item.path)
}
由于在main.js中挂载了router到vue实例上,所以可以使用$router属性,然后调用本身的push方法
存在问题:
点击首页跳转的是 ‘/’ ,原因是在当前路径再点击跳转当前路径会报错
解决:
在route的index.js中,加入重定向,意思是当路径是‘/’的时候重定向到‘/home’
const routes = [
//主路由
{
path:'/',
component:Main,
redirect:'/home',//重定向
children:[
//子路由
{path: '/home',component:Home},//首页
{path: '/user',component:User},//用户管理
{path: '/mall',component:Mall},//商品管理
{path: '/page1',component:PageOne},//页面1
{path: '/page2',component:PageTwo},//页面2
]
},
]
二级菜单的跳转:
<el-submenu v-for="item in hasChildren" :key="item.label" :index="item.label">
<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.path">
<el-menu-item @click="clickMenu(subItem)" :index="subItem.path">
{{subItem.label}}</el-menu-item>
</el-menu-item-group>
</el-submenu>
解决重复点击报错问题:
//点击菜单
clickMenu(item){
console.log(item)
//当页面路由与跳转的路由不一致才允许跳转
if(this.$route.path !== item.path && !(this.$route.path === '/home' && (item.path
=== '/')))
{this.$router.push(item.path)}
//$route表示当前页面路由,$router表示整个router实例
}
点击首页三次
六、header组件搭建与样式调整
header边框:
在component里新建CommonHeader.vue
<template>
<div class="header-container">
<div class="l-content"></div>
<div class="r-content"></div>
</div>
</template>
<script>
export default {
data(){
return{}
}
}
</script>
<style lang="less" scoped>
.header-container {
background-color: #333;
height: 60px;
}
</style>
在Main.vue中引入CommonHeader.vue组件
<script>
import CommonAside from '../components/CommonAside.vue'
import CommonHeader from '../components/CommonHeader.vue'
export default {
data(){
return{}
},
components:{
CommonAside,
CommonHeader
}
}
</script>
<template>
<div>
<el-container>
<el-aside width="200px">
<common-aside />
</el-aside>
<el-container>
<el-header>
<common-header />
</el-header>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>
去掉padding
在Main.vue中加入
<style scoped>
.el-header {
padding: 0
}
</style>
顶部左侧:
引入element-ui的icon
在CommonHeader.vue中
<style lang="less" scoped>
.header-container {
padding: 0 20px;
background-color: #333;
height: 60px;
display:flex;
justify-content:space-between;
align-items: center;
}
</style>
<template>
<div class="header-container">
<div class="l-content">
<el-button icon="el-icon-menu" size="mini"></el-button>
</div>
<div class="r-content"></div>
</div>
</template>
面包屑
<template>
<div class="header-container">
<div class="l-content">
<el-button icon="el-icon-menu" size="mini"></el-button>
<!-- 面包屑 -->
<span class="text">首页</span>
</div>
<div class="r-content"></div>
</div>
</template>
<style lang="less" scoped>
.header-container {
padding: 0 20px;
background-color: #333;
height: 60px;
display:flex;
justify-content:space-between;
align-items: center;
.text{
color:#fff;
font-size:14px;
margin-left: 10px;
}
}
</style>
顶部右侧:
引入element-ui的dropdown组件
<el-dropdown>
<span class="el-dropdown-link">
<img class="user" src="../assets/images/user.png">
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item>退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<template>
<div class="header-container">
<div class="l-content">
<el-button icon="el-icon-menu" size="mini"></el-button>
<!-- 面包屑 -->
<span class="text">首页</span>
</div>
<div class="r-content">
<el-dropdown>
<span class="el-dropdown-link">
<img class="user" src="../assets/images/user.png">
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item>退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
在 .header-container 中写入样式
.r-content{
.user{
width:40px;
height:40px;
border-radius:50%;
}
}
七、vuex实现左侧折叠
npm i vuex@3.6.2
在src下新建文件夹store,store下新建index.js,tab.js(管理菜单相关数据),
之前的isCollapse定义在字段内部(return)下
index.js中
import Vue from 'vue'
import Vuex from 'vuex'
import tab from './tab'
Vue.use(Vuex)
//创建vuex的实例,并对外暴露
export default new Vuex.Store(
{
modules:{
tab
}
}
)
tab.js中
export default {
state:{
isCollapse:false //控制菜单的展开还是收起
},
mutations: {
//修改菜单展开收起的方法
collapseMenu(state) {
state.isCollapse = !state.isCollapse
}
}
}
store实例挂载到vue实例中,需要在main.js中引入
import store from './store'
new Vue({
router,
store,
render: h => h(App),
}).$mount('#app')
第一步,在CommonHeader.vue中获取mutations方法
<el-button @click="handleMenu" icon="el-icon-menu" size="mini"></el-button>
通过commit方法调用对应的mutations
<script>
export default {
data(){
return{}
},
methods: {
handleMenu(){
this.$store.commit('collapseMenu')
}
}
}
</script>
第二步,在CommonAside.vue中获取store
在computed属性下写入(删除之前定义在data中的isCollapse)
isCollapse() {
return this.$store.state.tab.isCollapse
}
解决左侧展开显示问题:
在CommonAside.vue中
<h3>{{isCollapse ? '后台': '通用后台管理系统' }}</h3>
在Main.vue中,将width="200px"改为auto
<el-aside width="auto">
<common-aside />
</el-aside>
去掉缝隙,在 CommonAside.vue中,加入style
<style lang="less" scoped>
.el-menu {
border-right: none;
}
</style>
八、home组件布局
使用layout布局
使用card卡片,实现阴影效果
在Home.vue中,使用layout布局并加入一个card
<template>
<el-row>
<el-col :span="8">
<el-card class="box-card">
<div class="user">
<img src="../assets/images/user.png" alt="">
<div class="userinfo">
<p class="name">Admin</p>
<p class="access">超级管理员</p>
</div>
</div>
<div class="login-info">
<p>上次登陆时间:<span>2021-7-19</span></p>
<p>上次登陆地点:<span>武汉</span></p>
</div>
</el-card>
</el-col>
<el-col :span="16"><div class="grid-content bg-purple-light"></div></el-col>
</el-row>
</template>
<style lang="less" scoped>
.user {
padding-bottom:20px;
margin-bottom: 20px;
border-bottom: 1px solid #ccc;
display: flex;
align-items: center;
img {
margin-right: 40px;
width:150px;
height: 150px;
border-radius: 50%;
}
.userinfo {
.name {
font-size: 32px;
margin-bottom: 10px;
}
.access {
color:#999999;
}
}
}
.login-info {
p {
line-height: 28px;
font-size: 14px;
color:#999999;
span {
color:#666666;
margin-left: 10px;
}
}
}
</style>
九、home购买统计部份
在Home.vue中第二个<el-card>中引入<el-table>
<el-card>
<el-table
:data="tableData"
style="width: 100%">
<el-table-column
prop="name"
label="课程"
width="180">
</el-table-column>
<el-table-column
prop="todayBuy"
label="今日购买"
width="180">
</el-table-column>
<el-table-column
prop="monthBuy"
label="本月购买"
width="180">
</el-table-column>
<el-table-column
prop="totalBuy"
label="总购买"
width="180">
</el-table-column>
</el-table>
</el-card>
并在return中写入
tableData: [
{
name: 'oppo',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: 'vivo',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '苹果',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '小米',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '三星',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '魅族',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
}
]
加入样式:
<el-card style="margin-top:20px;height:460px;">
<el-table
:data="tableData"
style="width: 100%">
<el-table-column
prop="name"
label="课程">
</el-table-column>
<el-table-column
prop="todayBuy"
label="今日购买">
</el-table-column>
<el-table-column
prop="monthBuy"
label="本月购买">
</el-table-column>
<el-table-column
prop="totalBuy"
label="总购买">
</el-table-column>
</el-table>
</el-card>
简化代码:
在return中写入tableLabel
export default {
data(){
return{
tableData: [
{
name: 'oppo',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: 'vivo',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '苹果',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '小米',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '三星',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '魅族',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
}
],
tableLabel:{
name: '课程',
todayBuy: '今日购买',
monthBuy: '本月购买',
totalBuy: '总购买',
}
}
}
}
注释掉之前的 用v-for动态循环遍历tableLabel
<el-card style="margin-top:20px;height:460px;">
<el-table
:data="tableData"
style="width: 100%">
<!-- <el-table-column
prop="name"
label="课程">
</el-table-column>
<el-table-column
prop="todayBuy"
label="今日购买">
</el-table-column>
<el-table-column
prop="monthBuy"
label="本月购买">
</el-table-column>
<el-table-column
prop="totalBuy"
label="总购买">
</el-table-column> -->
<el-table-column v-for="(val,key) in tableLabel" :prop="key" :label="val" />
</el-table>
</el-card>
十、home订单统计实现
导入订单数据:
将数据渲染到页面右侧:
<el-col :span="16">
<div class="num">
<el-card v-for="item in countData" :key="item.name">
<i class="icon" :class="`el-icon-${item.icon}`"></i>
</el-card>
</div>
</el-col>
使用icon图标
渲染文字:
<el-col :span="16">
<div class="num">
<el-card v-for="item in countData" :key="item.name">
<i class="icon" :class="`el-icon-${item.icon}`"></i>
<div>
<p>{{ item.value }}</p>
<p>{{ item.name }}</p>
</div>
</el-card>
</div>
</el-col>
调整<el-card>样式,实现左右布局:
添加icon样式:
.num{
.icon{
width:80px;
height:80px;
font-size:30px;
text-align:center;
line-height:80px;
color:#fff;
}
}
加入icon颜色:
调整文字,垂直居中:
.detail{
display:flex;
flex-direction:column;
justify-content: center;
}
调整文字样式:
.detail{
margin-left: 15px;
display:flex;
flex-direction:column;
justify-content: center;
.price{
font-size: 30px;
margin-bottom: 10px;
line-height: 30px;
height: 30px;
}
.desc{
font-size: 14px;
color: #999;
text-align: center;
}
}
调整布局:
flex:wrap 自动换行:
.el-card{
width:32%;
margin-bottom: 20px;
}
调整边距:
十一、axios的基本使用和二次封装
npm install axios
封装axios,创建实例:
在src下新建文件夹utils中新建文件request.js
import axios from 'axios'
const http = axios.create({
//通用请求地址前缀
baseURL:'/api',
timeout:10000,//超时时间
})
export default http
添加拦截器:
import axios from 'axios'
const http = axios.create({
//通用请求地址前缀
baseURL:'/api',
timeout:10000,//超时时间
})
// 添加请求拦截器,绑定http实例
http.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器,绑定http实例
http.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
export default http
创建接口:
在src下新建文件夹api中新建index.js
import http from '../utils/request'
//请求首页数据
export const getData = () => {
//返回一个promise对象
return http.get('/home/getData')
}
调用接口:
在Home.vue中
调用成功
十二、mock数模拟实战
mock文档,用来前端模拟后端接口
# 安装
npm install mockjs
在api下新建mock.js
import Mock from 'mockjs'
//定义mock请求拦截
Mock.mock('/api/home/getData',function(){
//拦截到请求后的处理逻辑
console.log('拦截到了')
})
在main.js中引入
import './api/mock'
拦截到了
在mock中return 1
封装mock:
在api下新建文件夹mockServeData,中新建home.js和permission.js
在home.js中写入
// mock数据模拟
import Mock from 'mockjs'
// 图表数据
let List = []
export default {
getStatisticalData: () => {
//Mock.Random.float 产生随机数100到8000之间 保留小数 最小0位 最大0位
for (let i = 0; i < 7; i++) {
List.push(
Mock.mock({
苹果: Mock.Random.float(100, 8000, 0, 0),
vivo: Mock.Random.float(100, 8000, 0, 0),
oppo: Mock.Random.float(100, 8000, 0, 0),
魅族: Mock.Random.float(100, 8000, 0, 0),
三星: Mock.Random.float(100, 8000, 0, 0),
小米: Mock.Random.float(100, 8000, 0, 0)
})
)
}
return {
code: 20000,
data: {
// 饼图
videoData: [
{
name: '小米',
value: 2999
},
{
name: '苹果',
value: 5999
},
{
name: 'vivo',
value: 1500
},
{
name: 'oppo',
value: 1999
},
{
name: '魅族',
value: 2200
},
{
name: '三星',
value: 4500
}
],
// 柱状图
userData: [
{
date: '周一',
new: 5,
active: 200
},
{
date: '周二',
new: 10,
active: 500
},
{
date: '周三',
new: 12,
active: 550
},
{
date: '周四',
new: 60,
active: 800
},
{
date: '周五',
new: 65,
active: 550
},
{
date: '周六',
new: 53,
active: 770
},
{
date: '周日',
new: 33,
active: 170
}
],
// 折线图
orderData: {
date: ['20191001', '20191002', '20191003', '20191004', '20191005', '20191006', '20191007'],
data: List
},
tableData: [
{
name: 'oppo',
todayBuy: 500,
monthBuy: 3500,
totalBuy: 22000
},
{
name: 'vivo',
todayBuy: 300,
monthBuy: 2200,
totalBuy: 24000
},
{
name: '苹果',
todayBuy: 800,
monthBuy: 4500,
totalBuy: 65000
},
{
name: '小米',
todayBuy: 1200,
monthBuy: 6500,
totalBuy: 45000
},
{
name: '三星',
todayBuy: 300,
monthBuy: 2000,
totalBuy: 34000
},
{
name: '魅族',
todayBuy: 350,
monthBuy: 3000,
totalBuy: 22000
}
]
}
}
}
}
在mock.js中调用
import Mock from 'mockjs'
import homeApi from './mockServeData/home'
//定义mock请求拦截
Mock.mock('/api/home/getData', homeApi.getStatisticalData)
十三、首页可视化图表样式调整
解构赋值运用到函数参数
在Home.vue中
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
console.log(tableData)
})
}
打印成功
删除tableData中写死的数据
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
this.tableData = tableData
})
}
调整样式:
左右各加10px
<el-card style="height:280px">
<!-- 折线图 -->
</el-card>
<div class="graph">
<el-card style="height:260px"></el-card>
<el-card style="height:260px"></el-card>
</div>
.graph{
margin-top: 20px;
display: flex;
justify-content: space-between;
.el-card{
width:48%;
}
}
十四、echarts表格的折线图
npm i echarts@5.1.2
在Home.vue中引入echarts
import * as echarts from 'echarts'
初始化echarts实例
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
console.log(data)
this.tableData = tableData
// 基于准备好的dom,初始化echarts实例
const echarts1 = echarts.init(this.$refs.echarts1)
// 指定图表的配置项和数据
var option = {}
//处理数据xAxis
const { orderData } = data.data
const xAxis = Object.keys(orderData.data[0])
console.log(xAxis)
})
}
打印x轴数据
处理数据:
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
console.log(data)
this.tableData = tableData
// 基于准备好的dom,初始化echarts实例
const echarts1 = echarts.init(this.$refs.echarts1)
// 指定图表的配置项和数据
var echarts1Option = {}
//处理数据xAxis
const { orderData } = data.data
const xAxis = Object.keys(orderData.data[0])
echarts1Option.xAxis = xAxis
echarts1Option.legend = {
data:xAxis
}
echarts1Option.series = []
xAxis.forEach(key => {
echarts1Option.series.push({
name:key,
data:orderData.data.map(item => item[key]),
type:'line'
})
console.log(echarts1Option)
})
console.log(xAxis)
})
}
显示折线图
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
console.log(data)
this.tableData = tableData
// 基于准备好的dom,初始化echarts实例
const echarts1 = echarts.init(this.$refs.echarts1)
// 指定图表的配置项和数据
var echarts1Option = {}
//处理数据xAxis
const { orderData } = data.data
const xAxis = Object.keys(orderData.data[0])
const xAxisData = {
data:xAxis
}
echarts1Option.xAxis = xAxisData
echarts1Option.yAxis = {}
echarts1Option.legend = xAxisData
echarts1Option.series = []
xAxis.forEach(key => {
echarts1Option.series.push({
name:key,
data:orderData.data.map(item => item[key]),
type:'line'
})
console.log(echarts1Option)
// 使用刚指定的配置项和数据显示图表。
echarts1.setOption(echarts1Option)
})
console.log(xAxis)
})
}
十五、echarts表格的柱状图
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
console.log(data)
this.tableData = tableData
// 基于准备好的dom,初始化echarts实例
const echarts1 = echarts.init(this.$refs.echarts1)
// 指定图表的配置项和数据
var echarts1Option = {}
//处理数据xAxis
const { orderData,userData } = data.data
const xAxis = Object.keys(orderData.data[0])
const xAxisData = {
data:xAxis
}
echarts1Option.xAxis = xAxisData
echarts1Option.yAxis = {}
echarts1Option.legend = xAxisData
echarts1Option.series = []
xAxis.forEach(key => {
echarts1Option.series.push({
name:key,
data:orderData.data.map(item => item[key]),
type:'line'
})
console.log(echarts1Option)
// 使用刚指定的配置项和数据显示图表。
echarts1.setOption(echarts1Option)
//柱状图
// 基于准备好的dom,初始化echarts实例
const echarts2 = echarts.init(this.$refs.echarts2)
// 指定图表的配置项和数据
const echarts2Option = {
legend: {
// 图例文字颜色
textStyle: {
color: "#333",
},
},
grid: {
left: "20%",
},
// 提示框
tooltip: {
trigger: "axis",
},
xAxis: {
type: "category", // 类目轴
data: userData.map(item =>item.date),
axisLine: {
lineStyle: {
color: "#17b3a3",
},
},
axisLabel: {
interval: 0,
color: "#333",
},
},
yAxis: [
{
type: "value",
axisLine: {
lineStyle: {
color: "#17b3a3",
},
},
},
],
color: ["#2ec7c9", "#b6a2de"],
series: [
{
name:'新增用户',
data:userData.map(item =>item.new),
type:'bar'
},
{
name:'活跃用户',
data:userData.map(item =>item.active),
type:'bar'
}
],
}
echarts2.setOption(echarts2Option)
})
})
}
十六、echarts表格的饼状图
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
console.log(data)
this.tableData = tableData
// 基于准备好的dom,初始化echarts实例
const echarts1 = echarts.init(this.$refs.echarts1)
// 指定图表的配置项和数据
var echarts1Option = {}
//处理数据xAxis
const { orderData,userData,videoData } = data.data
const xAxis = Object.keys(orderData.data[0])
const xAxisData = {
data:xAxis
}
echarts1Option.xAxis = xAxisData
echarts1Option.yAxis = {}
echarts1Option.legend = xAxisData
echarts1Option.series = []
xAxis.forEach(key => {
echarts1Option.series.push({
name:key,
data:orderData.data.map(item => item[key]),
type:'line'
})
console.log(echarts1Option)
// 使用刚指定的配置项和数据显示图表。
echarts1.setOption(echarts1Option)
//柱状图
// 基于准备好的dom,初始化echarts实例
const echarts2 = echarts.init(this.$refs.echarts2)
// 指定图表的配置项和数据
const echarts2Option = {
legend: {
// 图例文字颜色
textStyle: {
color: "#333",
},
},
grid: {
left: "20%",
},
// 提示框
tooltip: {
trigger: "axis",
},
xAxis: {
type: "category", // 类目轴
data: userData.map(item =>item.date),
axisLine: {
lineStyle: {
color: "#17b3a3",
},
},
axisLabel: {
interval: 0,
color: "#333",
},
},
yAxis: [
{
type: "value",
axisLine: {
lineStyle: {
color: "#17b3a3",
},
},
},
],
color: ["#2ec7c9", "#b6a2de"],
series: [
{
name:'新增用户',
data:userData.map(item =>item.new),
type:'bar'
},
{
name:'活跃用户',
data:userData.map(item =>item.active),
type:'bar'
}
],
}
echarts2.setOption(echarts2Option)
//饼状图
// 基于准备好的dom,初始化echarts实例
const echarts3 = echarts.init(this.$refs.echarts3)
// 指定图表的配置项和数据
const echarts3Option = {
tooltip: {
trigger: "item",
},
color: [
"#0f78f4",
"#dd536b",
"#9462e5",
"#a6a6a6",
"#e1bb22",
"#39c362",
"#3ed1cf",
],
series: [
{
data:videoData,
type:'pie'
}
],
}
echarts3.setOption(echarts3Option)
})
})
}
十七、面包屑数据处理
在components中的CommonHeader.vue中,引入面包屑
<div class="l-content">
<el-button @click="handleMenu" icon="el-icon-menu" size="mini"></el-button>
<!-- 面包屑 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item><a href="/">活动管理</a></el-breadcrumb-item>
<el-breadcrumb-item>活动列表</el-breadcrumb-item>
<el-breadcrumb-item>活动详情</el-breadcrumb-item>
</el-breadcrumb>
</div>
定义数据部分:
在store的tab.js中
state:{
isCollapse:false ,//控制菜单的展开还是收起
tabsList: [
{
path: '/',
name: 'home',
label: '首页',
icon: 's-home',
url: 'Home/Home'
}
]//面包屑的数据
},
mutations: {
//修改菜单展开收起的方法
collapseMenu(state) {
state.isCollapse = !state.isCollapse
},
//更新面包屑数据
selectMenu(state,val){
console.log(val,'val')
}
}
在CommonAside中,调用mutations
更新数据:
在tab.js中
mutations: {
//修改菜单展开收起的方法
collapseMenu(state) {
state.isCollapse = !state.isCollapse
},
//更新面包屑数据
selectMenu(state,val){
console.log(val,'val')
//判断添加的数据是否为首页
if(val.name !== 'home'){
const index = state.tabsList.findIndex(item => item.name === val.name)
//如果不存在
if(index === -1){
state.tabsList.push(val)
}
}
}
}
使用:
在CommonHeader.vue中
<script>
import { mapState } from 'vuex'
export default {
data(){
return{}
},
methods: {
handleMenu(){
this.$store.commit('collapseMenu')
}
},
computed:{
...mapState({
tags:state => state.tab.tabsList
})
},
mounted(){
console.log(this.tabs,'tags')
}
}
</script>
页面渲染:
<div class="l-content">
<el-button @click="handleMenu" icon="el-icon-menu" size="mini"></el-button>
<!-- 面包屑 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="item in tags" :key="item.path" :to="{ path:
item.path }">{{item.label}}</el-breadcrumb-item>
</el-breadcrumb>
</div>
添加样式在CommonHeader中:
.l-content {
display: flex;
align-items: center;
/deep/.el-breadcrumb__item{
.el-breadcrumb__inner {
font-weight:normal;
&.is-link {
color:#666
}
}
&:last-child {
.el-breadcrumb__inner{
color: #fff;
}
}
}
}
十八、tag功能介绍&页面编写
在components中新建CommonTag.vue
<template>
<div class="tabs">
<el-tag
v-for="item in tags"
:key="item.path"
:closable="item.name !== 'home'"
:effect="$route.name === item.name ? 'dark' : 'plain'">
{{ item.label }}
</el-tag>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name:'CommonTag',
data() {
return {}
},
computed:{
...mapState({
tags:state => state.tab.tabsList
})
}
}
</script>
在Main.vue中引入CommonTag.vue
在router中的index.js中加入‘name’
十九、tag点击与删除事件
点击tag跳转:
methods:{
//点击tag跳转的功能
changeMenu(item){
// console.log(item)
this.$router.push({name:item.name})
}
}
点击删除:
methods:{
...mapMutations(['closeTag']),
//点击tag跳转的功能
changeMenu(item){
// console.log(item)
this.$router.push({name:item.name})
},
//点击tag删除的功能
handleClose(item,index){
//调用store中的mutations
this.closeTag(item)
const length = this.tags.length - 1
}
}
在tab.js中
点×有数据
只删除(还未跳转):
//删除指定的tag数据
closeTag(state,item){
// console.log(item,'item')
const index = state.tabsList.findIndex(val => val.name === item.name)
state.tabsList.splice(index,1)
}
删除并跳转:
在CommonTag.vue中
//点击tag删除的功能
handleClose(item,index){
//调用store中的mutations
this.closeTag(item)
const length = this.tags.length
//删除之后的跳转
if (item.name !== this.$route.name) {
return
}
//表示的是删除的最后一项
if(index === length) {
this.$router.push({
name:this.tags[index - 1].name
})
}
else{
this.$router.push({
name:this.tags[index].name
})
}
}
添加样式
<style lang="less" scoped>
.tabs{
padding: 20px;
.el-tag{
margin-right:15px;
cursor:pointer;
}
}
</style>
删除最后一个:
删除中间:
二默ermo: 厉害,手动点赞
61要当卷王!: 您好 请问这个zapper是数据和身份隐私保护的智能合约的那个zapper吗?