VUE2+Element-ui+Echarts图表
封装Echarts图表,如下效果图
Home组件代码块,使用的mock.js模拟数据封装
<template>
<div style="height: 400px">
<ChartsPart id="demo" :chartData="echartData.order"></ChartsPart>
</div>
</template>
<script>
//引入组件 略去
import ChartsPart from '@/components/EchartEasy.vue'
export default {
components: {
ChartsPart,
},
data() {
return {
echartData: {
// 订单折线图数据
order: {
// X轴数据
xData: [],
yData: {
type: 'value',
},
// series是x轴图表内,一个个的数据坐标轴
series: [],
},
// 用户柱状图数据
user: {
xData: [],
// series是x轴图表内,一个个的数据坐标轴
series: [],
},
// 视频饼状图数据
video: {
// series是x轴图表内,一个个的数据坐标轴
series: [],
},
},
}
},
methods: {
getTableData() {
this.$http.get('/home/getOnData').then((res) => {
// EChart图表数据
res = res.data
// console.log(res.data)
// 订单折线图
const order = res.data.orderData
// console.log(order)
// x轴数据
this.echartData.order.xData = order.date
// series图像渲染,x轴中的内置图表
// 第一步取出series中name部分-键名
// 通过 对象中的键值取出,需要数据的键名
let keyArray = Object.keys(order.data[0])
console.log(keyArray)
// 循环遍历每一项数据
keyArray.forEach((key) => {
// 在data数据中定义的echartData.order.series中存放数据
this.echartData.order.series.push({
name: key === 'wechat' ? '小程序' : key,
// key是一个变量,所以要[在这里装着],变量提升
data: order.data.map((item) => item[key]),
type: 'line', // 线性图
})
})
})
},
},
// 页面还没渲染完成,在这里调用接口比较好
created() {
// console.log(this.echartData.order)
// console.log(this.ChartTestData)
this.getTableData()
},
}
</script>
Echarts图表组件
<template>
<div style="height: 400px" ref="myEchart">echart</div>
</template>
<script>
import * as echarts from 'echarts'
export default {
name: 'EchartEasy',
// 数据部分是由,父组件传入的
props: {
chartData: {
// 数据肯定是一个对象
type: Object,
// 设置对象的默认值
// 使用default函数,再return返回
// 父组件修改内容,本身组件不受影响
default() {
return {
// x轴的数据
xData: [],
yData: {
type: 'value',
},
// y轴的值,是根据x轴中图表的数据进行动态增加或减少的
// yAxis: {
// type: 'value',
// },
// y轴的值,是根据x轴中图表的数据进行动态增加或减少的
// series是x轴图表内,一个个的数据坐标轴
series: [],
}
},
},
// 判断数据是否,带坐标轴的数据,进行渲染
isAxisChart: {
type: Boolean,
// 大部分数据是有坐标轴的,例如:折线图,柱形图;(饼状图是没有坐标轴的)
default: true,
},
},
data() {
return {
// 用于判断容器是否存在
offChart: null,
// 有坐标轴的配置
axisOption: {
// X轴数据渲染
xAxis: {
// 类目轴
type: 'category',
data: [],
},
// Y轴数据渲染
yAxis: [
{
// 连续的数据,根据x轴中series图表数据,动态改变
type: 'vlaue',
},
],
// 根据series渲染成(折线,住状图等)
series: [],
},
// 没有有坐标轴的配置
normalOption: {
// 例如饼状图,没有x轴或y轴,只需要一个series就足够了
// 根据series渲染成(折线,住状图等)
series: [],
},
}
},
// 计算属性
// 根据isAxisChart来判断,选择那个图表 axisOption 或 normalOption
computed: {
// 最终要去使用的options数据
options() {
return this.isAxisChart ? this.axisOption : this.normalOption
},
},
// 监听属性
watch: {
// chartData数据发生变化的时候监听, 对象要使用深度监听
chartData: {
// 如果发生变化
handler(newVal, oldVal) {
if (this.chart) {
// 使用echarts图表渲染新数据
this.chart.setOption(newVal)
} else {
// 调用Echarts图表渲染
this.initChart()
}
},
deep: true,
},
},
methods: {
initChart() {
// 在初始化图表的时候,先渲染图表数据
this.initChartData()
// 如果容器不存在
if (this.offChart) {
// setOption 使用刚指定的配置项和数据显示图表
// this.options 对应的是computed计算属性中的options
this.offChart.setOption(this.options)
console.log('容器不存在')
} else {
// 如果容器存在,init 初始化这个对象(通过ref的方法获取到这个dom)
this.offChart = echarts.init(this.$refs.myEchart)
this.offChart.setOption(this.options)
}
},
// 配置图表数据
initChartData() {
// 根据数据类型,判断渲染那种图表,例如折线图,或饼状图
// 如果是带坐标轴的图表
if (this.isAxisChart) {
// 折线图,x轴底部数据等于,父组件传入的数据
this.axisOption.xAxis.data = this.chartData.xData
// x轴中内置图表等于,父组件传入的数据
this.axisOption.yAxis = this.chartData.yData
this.axisOption.series = this.chartData.series
console.log('带坐标轴的数据')
console.log(this.chartData)
//
} else {
// 不带坐标轴的图表
console.log('normalOption不带坐标轴的数据')
}
},
},
}
</script>
安装所需依赖
cnpm i axios -S 安装axios接口请求
cnpm i mockjs 或 yarn add mockjs 安装mockjs生成模拟随机数据
cnpm i echarts 或 yarn add echarts 安装echarts图表
cnpm i element-ui -S 安装element-ui组件库
安装less
cnpm install less less-loader --sav-dev
cnpm i style-resources-loader --save
cnpm i vue-cli-plugin-style-resources-loader --save
vue.config.js配置如下
const { defineConfig } = require('@vue/cli-service')
const path = require('path')
module.exports = defineConfig({
lintOnSave: false,
transpileDependencies: true,
// 自动打开浏览器
devServer: {
// 端口号
port: 8888,
// 运行项目自动打开浏览器
open: true,
},
// 添加全局less变量
pluginOptions: {
'style-resources-loader': {
preProcessor: 'less',
patterns: [
// 路径
path.resolve(__dirname, './src/assets/less/_variable.less'),
// _variable.less文件中 @theme-color:#33aef0;(测试less是否正常使用)
],
},
},
})
在main.js中全局引入mock
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 全局配置 全局初始化css样式
import http from '@/axios/api/config'
import 'element-ui/lib/theme-chalk/index.css'
import './assets/less/reset.less'
import './mock' //引入mock虚拟数据
// 使用 第三方element-ui组件
import ElementUI from 'element-ui'
Vue.use(ElementUI)
// 将axios挂载到原型上面
// 在vue组件中,通过this.$http就可以调用axios实例
Vue.prototype.$http = http
Vue.config.productionTip = false
new Vue({
router,
store,
render: (h) => h(App),
}).$mount('#app')
新建mock文件夹
新建index,js文件内容
import Mock from "mockjs";
// 引入home文件随机生成的mock数据
import homeApi from './home'
// 设置200-2000毫米延时请求数据
Mock.setup({
timeout: '200-2000'
})
// 首页相关
// 拦截的是/home/getData , get请求,homeApi.getHomeData返回结果作为一个响应式,返回到拦截的ajax
Mock.mock(/\/home\/getOnData/, 'get', homeApi.getHomeData)
新建home.js内容
import Mock from 'mockjs'
// 图表数据
let List = []
// 使用mock模拟数据,渲染
export default {
getHomeData: () => {
for (let i = 0; i < 7; i++) {
List.push(
Mock.mock({
vue: Mock.Random.float(100, 8000, 0, 2),
wechat: Mock.Random.float(100, 8000, 0, 2),
ES6: Mock.Random.float(100, 8000, 0, 2),
Redis: Mock.Random.float(100, 8000, 0, 2),
React: Mock.Random.float(100, 8000, 0, 2),
springboot: Mock.Random.float(100, 8000, 0, 2)
})
)
}
return {
code: 20000,// 真实接口,返回200,这里写2万用于区分
// Random.float(min,max,dmin,dmax) 返回一个随机浮点数
// min:最小值,max:最大值,dmin:小数部分最小值,dmax:小数部分最大值
data: {
// 饼图
videoData: [
{
name: 'springboot',
value: Mock.Random.float(1000, 10000, 0, 2)
},
{
name: 'vue',
value: Mock.Random.float(1000, 10000, 0, 2)
},
{
name: '小程序',
value: Mock.Random.float(1000, 10000, 0, 2)
},
{
name: 'ES6',
value: Mock.Random.float(1000, 10000, 0, 2)
},
{
name: 'Redis',
value: Mock.Random.float(1000, 10000, 0, 2)
},
{
name: 'React',
value: Mock.Random.float(1000, 10000, 0, 2)
}
],
// 柱状图
userData: [
{
date: '周一',
new: Mock.Random.integer(1, 100),
active: Mock.Random.integer(100, 1000)
},
{
date: '周二',
new: Mock.Random.integer(1, 100),
active: Mock.Random.integer(100, 1000)
},
{
date: '周三',
new: Mock.Random.integer(1, 100),
active: Mock.Random.integer(100, 1000)
},
{
date: '周四',
new: Mock.Random.integer(1, 100),
active: Mock.Random.integer(100, 1000)
},
{
date: '周五',
new: Mock.Random.integer(1, 100),
active: Mock.Random.integer(100, 1000)
},
{
date: '周六',
new: Mock.Random.integer(1, 100),
active: Mock.Random.integer(100, 1000)
},
{
date: '周日',
new: Mock.Random.integer(1, 100),
active: Mock.Random.integer(100, 1000)
}
],
// 折线图
orderData: {
date: ['20191001', '20191002', '20191003', '20191004', '20191005', '20191006', '20191007'],
data: List
},
tableData: [
{
name: 'ES6',
todayBuy: Mock.Random.float(100, 1000, 0, 2),
monthBuy: Mock.Random.float(3000, 5000, 0, 2),
totalBuy: Mock.Random.float(40000, 1000000, 0, 2)
},
{
name: '小程序',
todayBuy: Mock.Random.float(100, 1000, 0, 2),
monthBuy: Mock.Random.float(3000, 5000, 0, 2),
totalBuy: Mock.Random.float(40000, 1000000, 0, 2)
},
{
name: 'Vue',
todayBuy: Mock.Random.float(100, 1000, 0, 2),
monthBuy: Mock.Random.float(3000, 5000, 0, 2),
totalBuy: Mock.Random.float(40000, 1000000, 0, 2)
},
{
name: 'springboot',
todayBuy: Mock.Random.float(100, 1000, 0, 2),
monthBuy: Mock.Random.float(3000, 5000, 0, 2),
totalBuy: Mock.Random.float(40000, 1000000, 0, 2)
},
{
name: 'React',
todayBuy: Mock.Random.float(100, 1000, 0, 2),
monthBuy: Mock.Random.float(3000, 5000, 0, 2),
totalBuy: Mock.Random.float(40000, 1000000, 0, 2)
},
{
name: 'Redis',
todayBuy: Mock.Random.float(100, 1000, 0, 2),
monthBuy: Mock.Random.float(3000, 5000, 0, 2),
totalBuy: Mock.Random.float(40000, 1000000, 0, 2)
}
]
}
}
}
}
home.less样式
.home{
// background-color: blueviolet;
//左侧,个人信息部分
.user{
display: flex;
align-items: center;
padding-bottom: 20px;
margin-bottom: 20px;
border-bottom: 1px solid #ccc;
img{
width: 150px;
height: 150px;
border-radius: 50%;
margin-right: 40px;
}
.userinfo{
&:extend(.user); // less中 的继承写法
.name{
max-width: 120px;
font-size: 32px;
margin-bottom: 20px;
overflow: hidden;
/*超出隐藏*/
text-overflow: ellipsis;
/*隐藏后添加省略号*/
white-space: nowrap;
/*强制不换行*/
}
.name:hover{
overflow: visible;
}
.access{
color: #999999;
}
}
}
// 登录时间,登录地址样式
.login-info{
p{
line-height: 28px;
font-size: 14px;
color: #999999;
span{
color: #666666;
margin-left: 60px;
}
}
}
// 右侧顶部,卡片部分
.num{
display: flex;
flex-wrap: wrap; //超出换行
justify-content: space-between; // 两端对齐
.el-card{
width: 32%;
margin-bottom: 20px;
/deep/ .el-card__body{
display: flex;
padding: 0;
}
}
.icon{
font-size: 30px;
width: 80px;
height: 80px;
text-align: center;
line-height: 80px;
color: #fff;
}
.detail{
margin-left:15px;
display: flex;
flex-direction: column; //垂直分布
justify-content: center; // 垂直居中
.num{
font-size: 30px;
margin-bottom: 10px;
}
.txt{
font-size: 14px;
text-align: center;
color: #999999;
}
}
}
// 右侧,底部each图表部分
.graph{
margin-top: 20px;
display: flex;
justify-content: space-between;
.el-card{
width: 48%;
}
}
}
封装axios请求文件(新建api文件夹,里面存放config.js)
import axios from "axios";
// 创建一个axios实例
const service = axios.create({
// 请求超时时间
timeout: 3000
})
// 添加请求拦截器(interceptors就是请求拦截器)
service.interceptors.request.use(
// 请求成功返回的参数
config => {
return config
},
err => {
console.log(err);
}
)
// 响应拦截器
service.interceptors.response.use(
response => {
let res = {}
// 判断状态码
res.status = response.status
res.data = response.data
return res
}, //失败返回参数
err => console.log(err)
)
// 千万不要忘记将,方法抛出去
export default service
版权归原作者 姜香小白鱼 所有, 如有侵权,请联系我们删除。