Vuex实现左侧菜单栏折叠
效果展示
思路分析及代码实现
首先我们要知道菜单栏的收缩,由el–menu的collapse属性控制:
我们通过分析可以知道:
菜单按钮的点击是在CommonHeader.vue组件中,而我们修改的collapse属性却在CommonAside.vue中,这是两个不同的组件。很明显这涉及到了组件间的通信问题,而我们很快就能想到几种处理组件间通信的方式:
export default {
state:{
isCollapse: false
},
mutations:{
COLLAPSE_MENU(state){
state.isCollapse = !state.isCollapse
}
}
}
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
import tab from "./tab"
export default new Vuex.Store({
//注意模块化是modules不要把s掉了
//模块化之后共享数据获得方式要注意一下
modules:{
tab
}
})
第四步:绑定菜单按钮的点击事件handleMenu
在CommonHeader组件中:
每次点击都调用store身上的commit方法,从而引动mutations身上的方法去更新state中的数据
完成了这些之后我们会发现我们的菜单栏确实可以收缩了,但是仍有两个问题:
漏洞完善
第二问题空隙问题
这个问题的产生原因是因为我们el–aside的宽度写死了,不管我们是否折叠菜单栏,这个盒子总会撑开300px,这也就导致了我们的CommonHeader一直被挤着伸展不开。所以我们把Main路由组件中的elside中的width由300px改为auto:
注意:这里不能把width属性删了,或者说不填。在css中我们不写默认值就是auto:
但这里el-side是Element-UI中的组件,这里的width默认值是300px:
Home组件的实现
完成Home组件之前我们先要进行布局操作,这里我们可以使用Element-UI的基本布局:
我们大致可以看到左右的大小关系为1:2:
所以我们可以用如下代码进行布局:
<el-row>
<el-col :span="8"></el-col>
<el-col :span="16"></el-col>
</el-row>
这样布局就完成了
这个时候如果你想去使用backgroundcolor上色看看布局的成效是看不出来的,因为布局所使用的容器只有宽没有高,我们需要往里面放东西把他慢慢地撑开
名片部分
<template>
<el-row>
<el-col :span="8">
<el-card class="box-card" shadow="always">
<div class="user-info">
<img src="../assets/user.png" alt="">
<div>
<p class="user-name">Admin</p>
<p class="user-identity">超级管理员</p>
</div>
</div>
<div >
<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>
<script>
export default {
name: "Home",
data(){
return{
}
}
}
</script>
<style lang="less" scoped>
img {
height: 150px;
margin-right: 40px;
border-radius: 50%;
}
.user-info {
display: flex;
align-items: center;
padding-bottom: 20px;
margin-bottom: 20px;
border-bottom: 1px solid #ccc;
.user-name {
font-size: 32px;
margin: 0;
margin-bottom: 10px;
}
.user-identity {
margin: 0;
}
}
span {
margin-left: 60px;
}
</style>
这个“Admin”和“超级管理员”我们不能分开放,因为我们发现他们两个整体都是在头像的中轴附近。
上半部分还有一个注意点,那就是我们使用了p标签,而p标签有一个默认样式就是上下都有一个外边距:
在这里我们要记得把他们去掉,达到与效果的最大契合度。
名片的下方部分,我们采用块级元素中放入行内块元素的方式进行构建,然后我们再给行内元素span设置做外边距即可。
table数据展示部分
效果展示:
完成表格我们直接在Element-UI中选取基础表格样式:
代码如下:
<template>
<el-table
:data="tableData"
style="width: 100%">
<el-table-column
prop="date"
label="日期"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址">
</el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
tableData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}]
}
}
}
</script>
当
el-table
元素中注入data
对象数组后,在el-table-column
中用prop
属性来对应对象中的键名即可填入数据,用label
属性来定义表格的列名。可以使用width
属性来定义列宽。
<el-card shadow="always" class="dataShow">
<el-table
:data="tableData"
style="width: 100%;height: 335px">
<el-table-column
v-for="(label,content) in dataLabel"
:prop="content"
:label="label"
>
</el-table-column>
</el-table>
</el-card>
数据:
<script>
export default {
name: "Home",
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
}
],
dataLabel: {
name:"课程",
todayBuy:"今日购买",
monthBuy:"本月购买",
totalBuy:"总购买",
}
}
}
}
</script>
订单统计部分实现
效果展示:
首先我们这里也是采用六个名片作为基底,然后再来看看我们的数据:
countData: [
{
name: "今日支付订单",
value: 1234,
icon: "success",
color: "#2ec7c9",
},
{
name: "今日收藏订单",
value: 210,
icon: "star-on",
color: "#ffb980",
},
{
name: "今日未支付订单",
value: 1234,
icon: "s-goods",
color: "#5ab1ef",
},
{
name: "本月支付订单",
value: 1234,
icon: "success",
color: "#2ec7c9",
},
{
name: "本月收藏订单",
value: 210,
icon: "star-on",
color: "#ffb980",
},
{
name: "本月未支付订单",
value: 1234,
icon: "s-goods",
color: "#5ab1ef",
},
],
<el-card v-for="item in countData" :key="item.name" class="countData" >
<i :class="`el-icon-${item.icon}`" :style="{backgroundColor:item.color,color:'#fff' }"></i>
<div>
<p class="value">¥{{item.value}}</p>
<p class="name">{{item.name}}</p>
</div>
</el-card>
我们知道如上的三个样式一般是对文字进行处理,但实际上他们是对字符框进行的一系列操作,而在这里他们同样可以对i标签中的图标进行作用
i {
height: 80px;
width: 80px;
/*可以通过font-size控制i中的图标大小,为什么??font-size本质上是控制字符框的高度 */
font-size: 30px;
line-height: 80px;
text-align: center;
}
如果我们尝试直接给el-card添加class属性然后再使用css对其进行样式的添加这样是行不通的!
因为这个el-card在被编译之后里面还会有一层div,class为el-card_body:
那么我们怎么给card添加样式呢?我们可以看看Element-UI的文档:
通过文档我们知道我们可以使用body–style进行样式的添加,往里面传入一个对象即可
然后我们就可以通过这种语法完成弹性布局。因为我们发现在card里面图标和文字是处于一行的,正好契合了弹性布局的特点。
<el-col :span="16" class="rightPart">
<el-card v-for="item in countData" :key="item.name" class="countData" :body-style="{display:'flex',padding:0}">
<i :class="`el-icon-${item.icon}`" :style="{backgroundColor:item.color,color:'#fff' }"></i>
<div>
<p class="value">¥{{item.value}}</p>
<p class="name">{{item.name}}</p>
</div>
</el-card>
这里我们还有一个注意点:
我们在给i标签添加样式的时候,是选择直接将样式写在标签里面。要注意这里我们传入的是一个对象,这是Vue中绑定样式的写法,如果想要深入了解可以移步我的另一篇文章:
Vue核心⑥(绑定样式)
如果我们还是使用原来的键值对形式然后使用分号隔开这是行不通的。因为我们的键也会被动态的解析,而这个值并不在我们的Vue实例对象身上所代理,所以会报错。
还是使用流体布局,但是我们要添加一个属性flex-wrap
属性让他换行,否则六个卡片全部挤在了一行。
然后这里我们将卡片的宽使用百分比进行界定,这样我们不用通过精密的计算就可以大致的在一行排上三个卡片。这个百分比我取的是32%
,我之所以不取33%是因为其中还要考虑卡片的外边距等相关因素,导致行内的第三个卡片可能会被挤到下一行去。
<template>
·······前一部分代码省略
<el-col :span="16" class="rightPart">
<el-card v-for="item in countData" :key="item.name" class="countData" :body-style="{display:'flex',padding:0}">
<i :class="`el-icon-${item.icon}`" :style="{backgroundColor:item.color,color:'#fff' }"></i>
<!-- 这里注意不能使用常规的style的动态的绑定语法,否则你的左值也会被解析,但他会发现Vue实例对象上没有这个值-->
<!-- 在Vue中如果对style做绑定要传入一个对象-->
<div>
<p class="value">¥{{item.value}}</p>
<p class="name">{{item.name}}</p>
</div>
</el-card>
</el-col>
</template>
<script>
export default {
name: "Home",
data() {
return {
countData: [
{
name: "今日支付订单",
value: 1234,
icon: "success",
color: "#2ec7c9",
},
{
name: "今日收藏订单",
value: 210,
icon: "star-on",
color: "#ffb980",
},
{
name: "今日未支付订单",
value: 1234,
icon: "s-goods",
color: "#5ab1ef",
},
{
name: "本月支付订单",
value: 1234,
icon: "success",
color: "#2ec7c9",
},
{
name: "本月收藏订单",
value: 210,
icon: "star-on",
color: "#ffb980",
},
{
name: "本月未支付订单",
value: 1234,
icon: "s-goods",
color: "#5ab1ef",
},
],
}
}
}
</script>
<style lang="less" scoped>
p {
margin: 0;
}
.countData {
width: 32%;
margin-right: 9px;
margin-bottom: 14px;
i {
height: 80px;
width: 80px;
font-size: 30px;
line-height: 80px;
text-align: center;
}
.value {
font-size: 30px;
margin-bottom: 10px;
}
.name {
text-align: center;
color: #999;
font-size: 14px;
}
div {
display: flex;
flex-direction: column;
justify-content:center;
margin-left: 15px;
}
}
.rightPart {
display: flex;
flex-wrap:wrap;
}
</style>
首页可视化图表样式调整
这一个部分我们主要干两件事:
首先我们将静态数据全部替换成mock的数据,直接在mounted钩子函数中对tableData中的数据进行赋值即可:
布局方面无非就是调调大小,设设边距,结合开发者工具很容易办到,这里就不使用大篇幅的内容进行赘述,我们直接上代码:
<el-card class="zhexian">
折线图部分
</el-card>
<div class="smallpics">
<el-card class="pic" >
柱状图
</el-card>
<el-card class="pic">
扇形图
</el-card>
</div>
代码位置:
样式:
.el-col {
padding: 10px;
}
.zhexian {
width: 100%;
height: 250px;
}
.smallpics {
display: flex;
justify-content: space-between;
width: 100%;
margin-top: 10px;
.pic {
height: 195px;
width: 48%;
}
}
ECharts基本使用
- 在绘图前我们需要为 ECharts 准备一个定义了高宽的 DOM 容器
- 然后就可以通过 echarts.init 方法初始化一个 echarts 实例并通过 setOption 方法生成一个简单的柱状图
下面是完整代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>ECharts</title>
<!-- 引入刚刚下载的 ECharts 文件 -->
<!-- 当然你也可以使用cdn引入 -->
<!-- <script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script> -->
<script src="echarts.js"></script>
</head>
<body>
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>
其中option中的参数如果我们有看不懂的地方可以直接查看官方文档:
在本项目中我们安装的ECharts依赖是5.1.2版本的:
npm i echarts@5.1.2
折线图
首先我们先在我们的Home组件种引入Echarts:
在动手之前有几个注意点要注意:
首先我们先拿到DOM,这里我们使用vue中的ref:
然后我们对其进行初始化并指定图表的配置项和数据:
// 基于准备好的dom,初始化echarts实例
const echarts1 = echarts.init(this.$refs.echarts1)
// 指定图表的配置项和数据
var echarts1Option = {}
注意:
这里有可能会报错TypeError: this.dom.getContext is not a function
如果是这样的话就使用document.getElement方法获取标签!
然后我们就要往里面放数据了,先来分析一下我们拿到的数据结构:
要拿到折线图的legend我们需要遍历Array中一个对象的全部key,这里我们直接使用Object身上的keys方法,然后横坐标我们直接手敲:
const {orderData} = data.data
const legend = Object.keys(orderData[0])
echarts1Option.xAxis = {
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
type:'category',
boundaryGap:true
}
echarts1Option.legend = {
data:legend
}
echarts1Option.yAxis = {}
在这里我对xAxis中的配置项做出解释:
然后我们需要将每个横坐标对应的数据拿到进行series项的配置:
echarts1Option.series = []
xAxis.forEach(key => {
echarts1Option.series.push({
name: key,
data: orderData.data.map(item => item[key]),
type: 'line'
})
})
这里的map函数返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值:
echarts1.setOption(echarts1Option)
最终效果:
柱状图
我们实现了折现图之后,柱状图和饼状图的制作流程应该就已经不是问题了,我们简单地说一下流程。
仍然是在ECharts中找一个例子,这里我们以下图的这个柱状图为例子:
我们的代码部分:
// 接下来我们制作柱状图
const echarts2 = echarts.init(document.getElementsByClassName('zhuzhuang').item(0))
const {userData} = data.data
let echarts2Option = {}
echarts2Option.xAxis = {
type: 'category',
data: userData.map(item => item['date'] )
}
echarts2Option.yAxis = {};
echarts2Option.series = {
data: userData.map(item => item['active'] ),
type: 'bar',
showBackground: true,
backgroundStyle: {
color: 'rgba(250, 220, 95, 0.8)'
}
}
// 使用刚指定的配置项和数据显示图表。
echarts2.setOption(echarts2Option)
饼状图
代码如下:
//接下来我们来制作饼图
// 基于准备好的dom,初始化echarts实例
const echarts3 = echarts.init(document.getElementsByClassName('bingzhuang').item(0))
// 指定图表的配置项和数据
let echarts3Option = {}
const {videoData} = data.data
echarts3Option.tooltip = {
trigger: 'item',
}
echarts3Option.legend = {
type: 'scroll',
orient: 'vertical',
right: 5,
top: 20,
bottom: 20,
data: videoData.map(item => item['name'])
}
echarts3Option.series = [
{
name: 'Area Mode',
type: 'pie',
radius: [20, 100],
roseType: 'area',
itemStyle: {
borderRadius: 5
},
data: videoData
}
]
// 使用刚指定的配置项和数据显示图表。
echarts3.setOption(echarts3Option)
最终效果:
附:项目中对axios的使用(二次封装)
在请求配置中只有 url 是必需的。如果没有指定 method,请求将默认使用 get 方法。
请求配置非常的多,我们可以自行在axios官网上进行查找:
第一次封装
第一步:首先在src目录下新建一个utils文件夹(文件夹名字按个人喜好)并在其目录下创建一个index.js文件用于axios第一次封装。
在src目录下index.js中代码如下图,它里面有请求拦截器和响应拦截器,对请求过程和响应响应过程做出基本的提交和反馈,方便我们直观的观察到请求过程中所遇到的问题:
import axios from 'axios'
const http = axios.create({
// 通用请求的地址前缀
baseURL: '/api',
timeout: 10000, // 超时时间
})
// 添加请求拦截器
http.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
http.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
export default http
第二次封装
第二步:在src文件夹下创建api文件,用于axios的二次封装,通过export将方法暴露出去,方便在所需页面调用。
import http from '../utils/request'
// 请求首页数据
export const getData = () => {
// 返回一个promise对象
return http.get('/home/getData')
}
export const getUser = (params) => {
console.log(params, 'params')
// 返回用户列表
//请求参数 (注意这里写的是params是因为是get请求,如果是其他请求例如post、put请求要写为data)
return http.get('/user/getUser', params)
}
我们在页面中调用这里的getData方法之后得到的直接就是一个Promise对象,我们可以直接用它
.then
拿到我们的数据
第三步:在页面中引用Http.js文件,调用自己所配置好的请求方法,配合asnyc和awit异步请求方法,最终我们就可以直接的获取到请求的数据信息!
附:使用Mock.js完成数据模拟
首先我们安装依赖:
npm install mockjs
然后我们在api文件夹下创建一个mock.js文件,在里面来引入我们的mock:
方法详解:
Mock.mock( rurl?, rtype?, template|function( options ) )
rurl
:可选。表示需要拦截的 URL,可以是 URL 字符串或 URL 正则。例如 //domain/list.json/、‘/domian/list.json’。rtype
:可选。表示需要拦截的 Ajax 请求类型。例如 GET、POST、PUT、DELETE 等。template
:可选。表示数据模板,可以是对象或字符串。例如 { ‘data|1-10’:[{}] }、‘@EMAIL’。function(options)
:可选。表示用于生成响应数据的函数。options
:指向本次请求的 Ajax 选项集,含有 url、type 和 body 三个属性
然后我们需要在main.js对mock进行引入:
通过这个控制台可以看到我们的请求被成功拦截了:
但是data是空的,我们可以让方法返回一些东西,这样data里面就有数据了:
然后再开看看相应的数据:
接下来我们就可以使用mock进行数据的测试了。但是此时我们发现我们mock中的function写死在这里了,按照我们整个项目中的规则,我们是希望把一些相同的逻辑和功能封装在一起。
我们首先在api下面新建一个文件目录,例如这里我就取名mockServerData,我们在下面新建两个文件:
// 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文件对刚才的function进行修改:
此时我们来测试一下:
ok大功告成!
原文地址:https://blog.csdn.net/zyb18507175502/article/details/127498630
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_44834.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!