一、引用步骤:
1、先引入echarts库:
如果用的页面比较多,可以在main.js中全局引入echarts库;如果用的页面不多,可以单独引入。这里采用全局引入:
import Vue from 'vue'
import 'normalize.css/normalize.css'// A modern alternative to CSS resets
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import locale from 'element-ui/lib/locale/lang/zh-CN' // lang i18n
import '@/styles/index.scss' // global css
import App from './App'
import router from './router'
import store from './store'
import '@/icons' // icon
import '@/permission' // permission control
import VueJsonp from 'vue-jsonp'
import echarts from 'echarts'
Vue.use(VueJsonp)
Vue.use(ElementUI, { locale })
Vue.config.productionTip = false
Vue.prototype.$echarts = echarts
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})
2、具体图表引用:参数参考echarts官网https://echarts.apache.org/en/index.html
这里写了几个常用的统计图:
代码:
<template>
<div class="container">
<el-row gutter="5">
<!--柱状图-->
<el-col span="6">
<el-card class="card">
<div style="height:200px" ref="bar"></div>
</el-card>
</el-col>
<!--折线图-->
<el-col span="8">
<el-card>
<div style="height:200px;margin-left:0px" ref="line"></div>
</el-card>
</el-col>
<!--饼图-->
<el-col span="10">
<el-card>
<div style="height:200px;margin-left:0px" ref="pie"></div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
data() {
return {
//柱状图
barList: {
title: { text: "柱状图" },
tooltip: {},
xAxis: {
data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
},
yAxis: {},
series: [
{
name: "销量",
type: "bar",
data: [5, 20, 36, 10, 10, 20]
}
]
},
//折线图
lineList: {
title: { text: "折线图" },
xAxis: {
type: "category",
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
},
yAxis: {
type: "value"
},
series: [
{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: "line"
}
]
},
//饼图
pieList: {
title: {
text: "饼图",
subtext: "虚构数据",
left: "center"
},
legend: {
// orient: 'vertical',
// top: 'middle',
bottom: 10,
data: ["西凉", "益州", "兖州", "荆州", "幽州"]
},
series: [
{
type: "pie",
radius: "65%",
center: ["50%", "50%"],
selectedMode: "single",
data: [
{
value: 1548,
name: "幽州",
label: {
formatter: [
"{title|{b}}{abg|}",
" {weatherHead|天气}{valueHead|天数}{rateHead|占比}",
"{hr|}",
" {Sunny|}{value|202}{rate|55.3%}",
" {Cloudy|}{value|142}{rate|38.9%}",
" {Showers|}{value|21}{rate|5.8%}"
].join("\n"),
backgroundColor: "#eee",
borderColor: "#777",
borderWidth: 1,
borderRadius: 4,
rich: {
title: {
color: "#eee",
align: "center"
},
abg: {
backgroundColor: "#333",
width: "100%",
align: "right",
height: 25,
borderRadius: [4, 4, 0, 0]
},
Sunny: {
height: 30,
align: "left",
backgroundColor: {
//image: weatherIcons.Sunny
}
},
Cloudy: {
height: 30,
align: "left",
backgroundColor: {
//image: weatherIcons.Cloudy
}
},
Showers: {
height: 30,
align: "left",
backgroundColor: {
//image: weatherIcons.Showers
}
},
weatherHead: {
color: "#333",
height: 24,
align: "left"
},
hr: {
borderColor: "#777",
width: "100%",
borderWidth: 0.5,
height: 0
},
value: {
width: 20,
padding: [0, 20, 0, 30],
align: "left"
},
valueHead: {
color: "#333",
width: 20,
padding: [0, 20, 0, 30],
align: "center"
},
rate: {
width: 40,
align: "right",
padding: [0, 10, 0, 0]
},
rateHead: {
color: "#333",
width: 40,
align: "center",
padding: [0, 10, 0, 0]
}
}
}
},
{ value: 535, name: "荆州" },
{ value: 510, name: "兖州" },
{ value: 634, name: "益州" },
{ value: 735, name: "西凉" }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)"
}
}
}
]
}
};
},
mounted() {
this.initCharts();
},
methods: {
initCharts() {
//柱状图
let bar = this.$echarts.init(this.$refs.bar);
bar.setOption(this.barList);
//折线图
let line = this.$echarts.init(this.$refs.line);
line.setOption(this.lineList);
//饼图
let pie = this.$echarts.init(this.$refs.pie);
pie.setOption(this.pieList);
}
}
};
</script>
<style scoped>
.container {
height: 100%;
width: 100%;
margin: 0 0;
}
.card {
margin-left: 0px;
}
</style>
二、动态加载echarts图表数据常见问题:
1、注意如果是从后台获取数据渲染,需要写高度和宽度,否则图表可能不展示
<!-- @format -->
<template>
<div class="container">
<el-col>
<div ref="pie" class="pie-div" ></div>
</el-col>
</div>
</template>
<script>
export default {
name: 'schoolProductOverviewInfo',
props: {
schoolProjectsList: {
required: true,
type: Array
}
},
data() {
return {
pieChart: '',
//饼图
pieData: {
graphic: [
{
//环形图中间添加文字
type: 'text', //通过不同top值可以设置上下显示
left: 'center',
top: '45%',
style: {
text: '',
textAlign: 'center',
fill: 'black', //文字的颜色
width: 30,
height: 30,
fontSize: 30,
fontFamily: 'Microsoft YaHei'
}
}
],
series: [
{
name: '项目饼图',
type: 'pie',
radius: ['55%', '100%'],
avoidLabelOverlap: false,
label: {
normal: {
position: 'inside',
show: true, //控制显隐
textStyle: {
color: '#F2F2F2',
fontSize: 10
}
}
},
emphasis: {
label: {
show: true,
fontSize: '20',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
color: [],
data: []
}
]
}
};
},
created() {
this.initProjectPieData();
},
mounted() {
setTimeout(() => {
this.initCharts();
}, 500);
},
methods: {
initCharts() {
let pie = this.$echarts.init(this.$refs.pie);
this.pieChart = pie;
pie.setOption(this.pieData, true);
},
//计算数据
initProjectPieData() {
let pieDataList = [];
let colorList = [];
let color = '';
let pieData = {};
//0项目1,1项目2,2项目3,3项目4,4项目5
for (var i = 0; i < 5; i++) {
var projects = this.schoolProjectsList.filter(item => {
return item.projectStatus === i + '';
});
let name = '';
if (i === 0) {
name = '项目1';
color = '#C6D9F1';
} else if (i === 1) {
name = '项目2';
color = '#558ED5';
} else if (i === 2) {
name = '项目3';
color = '#F79646';
} else if (i === 3) {
name = '项目4';
color = '#D3D3D3';
} else if (i === 4) {
name = '项目5';
color = '#00bfbf';
}
if (projects.length > 0) {
pieData = { value: projects.length, name: name + ' ' + projects.length };
pieDataList.push(pieData);
colorList.push(color);
}
}
this.pieData.series[0].data = pieDataList;
this.pieData.color = colorList;
if (this.schoolProjectsList.length > 0) {
this.pieData.graphic[0].style.text = this.schoolProjectsList.length;
}
}
}
};
</script>
<style scoped lang="less">
.pie-div {
height: 200px;
width: 200px;
margin: 0px;
}
</style>
2、数据异步获取图表不渲染:动态加载,由于数据是从后台异步获取的,如果响应比较慢而echarts先初始化了可能会导致页面为空不渲染新数据,解决方法:
(1)方法一:在created钩子函数中获取数据,在mounted中延迟初始化echarts:如我这里延迟了500ms,差不多等数据已经响应了再初始化echarts
mounted() {
setTimeout(() => {
this.initCharts();
}, 500);
},
(2)方法二:加入watch监听,监听option数据,注意一开始需要给option的data赋值(为[]),否则监听option不会监听data属性:
<!-- @format -->
<template>
<div class="container">
<el-row :gutter="20">
<!--类型饼图-->
<el-col :span="4" :offset="1">
<div ref="userTypePie" class="pie-div" ></div>
</el-col>
<!--等级折线图饼图-->
<el-col :span="8" :offset="1">
<div ref="userLevel" class="level-div" ></div>
</el-col>
<!--来源饼图-->
<el-col :span="4" :offset="1">
<div ref="userSourcePie" class="pie-div" ></div>
</el-col>
</el-row >
</div>
</template>
<script>
export default {
data() {
return {
userTypePie: '',
userLevel: '',
userSourcePie: '',
userTypePieData: {
title: {
text: '用户类型',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}, {c}, {d}%'
},
series: [
{
name: '',
type: 'pie',
radius: '65%',
center: ['50%', '50%'],
selectedMode: 'single',
label: {
normal: {
position: 'inside',
show: true,
textStyle: {
color: '#F2F2F2',
fontSize: 10
}
}
},
data: [
{
value: 1548,
name: '幽州'
},
{ value: 535, name: '荆州' },
{ value: 510, name: '兖州' },
{ value: 634, name: '益州' },
{ value: 735, name: '西凉' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
},
userLevelData: {
title: {
text: '用户定级',
left: 'center'
},
xAxis: {
type: 'category',
data: [ 'A', 'B', 'C', 'D']
},
yAxis: {
type: 'value'
},
series: [
{
data: [],
type: 'bar',
showBackground: true,
backgroundStyle: {
color: 'rgba(220, 220, 220, 0.8)'
}
}
]
},
userSourcePieData: {
title: {
text: '用户来源',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
series: [
{
name: '',
type: 'pie',
radius: '65%',
center: ['50%', '50%'],
selectedMode: 'single',
label: {
normal: {
position: 'inside',
show: true,
textStyle: {
color: '#F2F2F2',
fontSize: 10
}
}
},
data: [
{
value: 1548,
name: '幽州'
},
{ value: 535, name: '荆州' },
{ value: 510, name: '兖州' },
{ value: 634, name: '益州' },
{ value: 735, name: '西凉' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
};
},
created() {
this.getBaseUserInfo();
},
mounted() {
this.initCharts();
},
methods: {
getBaseUserInfo() {
this.$api['user/getUserInfo']({}).then(data => {
let userLevelMap = data.userLevelMap;
let userLevelData = [];
userLevelData.push(userLevelMap['A'].length);
userLevelData.push(userLevelMap['B'].length);
userLevelData.push(userLevelMap['C'].length);
userLevelData.push(userLevelMap['D'].length);
this.userLevelData.series[0].data = userLevelData;
});
},
initCharts() {
//类型饼图
this.userTypePie = this.$echarts.init(this.$refs.userTypePie);
this.userTypePie.setOption(this.userTypePieData, true);
//定级折线图
this.userLevel = this.$echarts.init(this.$refs.userLevel);
this.userLevel.setOption(this.userLevelData, true);
//来源饼图
this.userSourcePie = this.$echarts.init(this.$refs.userSourcePie);
this.userSourcePie.setOption(this.userSourcePieData, true);
}
},
watch: {
userLevelData: {
handler(newVal, oldVal) {
if (this.userLevel) {
if (newVal) {
this.userLevel.setOption(newVal);
} else {
this.userLevel.setOption(oldVal);
}
} else {
//如果写了immediate: true,下面的代码需要去掉,因为vue初始化生命周期获取不到DOM
// this.userLevel = this.$echarts.init(this.$refs.userLevel);
// this.userLevel.setOption(this.userLevelData, true);
}
},
immediate: true,
deep: true
}
}
};
</script>
<style lang="less" scoped>
.container {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
.level-div {
height: 250px;
width: 300px;
margin: 0px;
}
.pie-div {
height: 200px;
width: 200px;
margin: 0px;
}
}
</style>
三、echarts图表宽度自适应问题:
1、上面说了,如果是从后台获取数据渲染,需要写高度和宽度,否则图表可能不展示。但是宽度写死了,浏览器窗口大小改变会使echarts图表显的很挤或者很空,解决方法:css设置高度,宽度写100%,浏览器窗口改变时,在windows.onresize中重置图表大小达到自适应。
<template>
<div class="container">
<el-row :gutter="20">
<!--类型饼图-->
<el-col :span="4" :offset="1">
<div ref="userTypePie" class="pie-div" ></div>
</el-col>
<!--等级折线图饼图-->
<el-col :span="8" :offset="1">
<div ref="userLevel" class="level-div" ></div>
</el-col>
<!--来源饼图-->
<el-col :span="4" :offset="1">
<div ref="userSourcePie" class="pie-div" ></div>
</el-col>
</el-row >
</div>
</template>
<script>
......
mounted() {
//类型饼图
this.userTypePie = this.$echarts.init(this.$refs.userTypePie);
this.userTypePie.setOption(this.userTypePieData, true);
//定级折线图
this.userLevel = this.$echarts.init(this.$refs.userLevel);
this.userLevel.setOption(this.userLevelData, true);
//来源饼图
this.userSourcePie = this.$echarts.init(this.$refs.userSourcePie);
this.userSourcePie.setOption(this.userSourcePieData, true);
//宽度自适应
window.onresize = () => {
this.userTypePie.resize();
this.userLevel .resize();
this.userSourcePie .resize();
};
},
</script>
<style lang="less" scoped>
.container {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
.pie-div {
height: 250px;
width: 100%;
margin: 0px;
}
.level-div {
height: 250px;
width: 100%;
margin: 0px;
}
}
</style>
2、一个页面有多个图表,resize()方法只生效一个,解决方法:在使用window.onresize监听窗口变化时,要使用DOM二级绑定方式:addEventListener方式。将window.onresize改为window.addEventListener,如:
window.addEventListener("resize",()=>{
brokenLine.resize();
});
3、图表宽度设置为100%,实际渲染为100px问题,解决方法:
<div class="container" id="container" ref="container">
<div ref="gaugeChart" class="gauge-div" id="gaugeChart"></div>
</div>
mounted() {
this.initCharts();
},
methods: {
resizeGaugeWidth() {
//宽度
// let outWidth = document.getElementById('container').clientWidth;
let outWidth = this.$refs.container.clientWidth;
console.info('宽度:' + outWidth);
this.$refs.gaugeChart.style.width = outWidth + 'px';
},
initCharts() {
this.resizeGaugeWidth();
this.gaugeChart = this.$echarts.init(this.$refs.gaugeChart);
this.gaugeChart.setOption(this.gaugeOption, true);
//宽度自适应
window.addEventListener('resize', () => {
this.resizeGaugeWidth();
this.gaugeChart.resize();
});
}
}
.container {
.gauge-div {
height: 150px;
width: 100%;
margin: 0px;
display: inline;
}
}
强制赋值宽度: