创建两个文件夹 1.resize.js 处理组件的自适应
export default {
data() {
return {
$_resizeHandler: null
}
},
mounted() {
this.initListener()
},
activated() {
if (!this.$_resizeHandler) {
// avoid duplication init
this.initListener()
}
this.resize()
},
beforeDestroy() {
this.destroyListener()
},
deactivated() {
this.destroyListener()
},
methods: {
$_sidebarResizeHandler(e) {
if (e.propertyName === 'width') {
this.$_resizeHandler()
}
},
initListener() {
this.$_resizeHandler = debounce(() => {
this.resize()
}, 100)
window.addEventListener('resize', this.$_resizeHandler)
},
destroyListener() {
window.removeEventListener('resize', this.$_resizeHandler)
this.$_resizeHandler = null
},
resize() {
// 单个绘图实例用chart,否则用charts
const { chart, charts } = this
if (Array.isArray(charts)) {
charts.forEach(chart => {
chart && chart.resize()
})
} else {
chart && chart.resize()
}
}
}
}
function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result
const later = function () {
// 据上一次触发时间间隔
const last = +new Date() - timestamp
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last)
} else {
timeout = null
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
if (!immediate) {
result = func.apply(context, args)
if (!timeout) context = args = null
}
}
}
return function (...args) {
context = this
timestamp = +new Date()
const callNow = immediate && !timeout
// 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait)
if (callNow) {
result = func.apply(context, args)
context = args = null
}
return result
}
}
2.baseChart.js 抽取公共属性处理逻辑
import resize from './resize.js'
export default {
mixins: [resize],
props: {
chartData: {
type: Object,
require: true,
default: () => { }
},
chartOption: {
type: Object,
default: () => { }
},
chartId: {
type: String,
require: true,
default: 'chart'
},
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '400px'
}
},
data() {
return {
chart: null
}
},
watch: {
chartData: {
deep: true,
handler(chartData) {
this.updateOption(this.getOption(chartData))
}
}
},
mounted() {
setTimeout(() => {
document.querySelectorAll(`#${this.chartId}`).forEach(dom => {
this.initChart(dom)
});
}, 0)
},
beforeDestroy() {
if (this.chart) {
this.chart.dispose()
this.chart = null
}
},
methods: {
initChart(dom) {
// if (dom) {
// this.chart = this.$echarts.init(dom)
// } else {
// //customed 已注册的主题名称
// // this.chart = this.$echarts.init(document.getElementById(this.chartId) // 'customed'
// // )
// }
this.chart = this.$echarts.init(dom // 'customed'
)
console.log(this.chartId);
const option = this.getOption(this.chartData)
this.updateOption(option)
},
updateOption(option) {
const { seriesData = [] } = this.chartData
if (seriesData.length === 0) {
this.chart.clear()
this.chart.showLoading({
text: '暂无数据',
color: '#fff',
textColor: '#909399',
fontSize: '14px'
})
} else {
this.chart.hideLoading()
this.chart.setOption(option, true)
}
},
getOption(data) {
const option = {}
// 合并传入option
Object.assign(option, this.chartOption)
return option
}
}
}
封装一个柱状图
<template>
<div :id="chartId" :class="className" :style="{width: width, height:height}"></div>
</template>
<script>
import baseChart from '@/utils/baseChart.js'
export default {
mixins: [baseChart],
methods: {
getOption() {
const {
seriesData,
xAxisData
} = this.chartData
let option = {
xAxis: {
type: 'category',
data: xAxisData
},
yAxis: {
type: 'value'
},
series: seriesData
};
//合并option,处理组件需要覆盖option属性
option = Object.assign(option, this.chartOption)
return option
}
}
}
</script>
在封一个饼图
<template>
<div :id="chartId" :class="className" :style="{width: width, height:height}"></div>
</template>
<script>
import baseChart from '@/utils/baseChart.js'
export default {
mixins: [baseChart],
methods: {
getOption() {
const {
seriesData
} = this.chartData
const option = {
tooltip: {
trigger: 'item'
},
legend: {
top: '5%',
left: 'center'
},
series: [{
name: 'Access From',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '40',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: seriesData
}]
};
return option
}
}
}
</script>
调用组件传数据
<template>
<div class="chart-page" id="chart">
<Bar :chart-data="barChartData" :chart-option="{}" chart-id="barChart"
class="chart" />
</div>
</template>
<script>
import Bar from '../components/Bar.vue'
export default {
name: "ChartDemo",
components: {
Bar,
},
data() {
return {
barChartData: {},
pieChartData: {
seriesData: []
}
}
}
},
mounted() {
this.initPage()
},
methods: {
initPage() {
//axios
this.barChartData = {
xAxisData: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
seriesData: [{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar'
}]
}
this.pieChartData = {
seriesData: [{
value: 1048,
name: 'Search Engine'
},
{
value: 735,
name: 'Direct'
},
{
value: 580,
name: 'Email'
},
{
value: 484,
name: 'Union Ads'
},
{
value: 300,
name: 'Video Ads'
}
]
}
}
}
}
</script>
<style scoped>
.chart-page {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 100%;
}
.chart {
height: 400px ;
width: 500px ;
}
</style>