前言
项目中经常使用echarts,也没有很优雅的使用,一直想做一个自己的代码库,将平时工作中的demo存放
github: gitee.com/shen_xu_he/…
项目说明
技术栈: vue2 + router + vuex + echarts(5.x) + elementUI
封装目的: 封装 echart 基本设施,能在项目中达到开箱即用的效果 封装思想:
- 抽离引入的echarts,注册及逻辑(按需导入)
- 封装echarts 组件
- 实现 屏幕自适应、组件销毁时释放实例、数据响应式等
- 这种方式可能满足不了所有场景,但是足以应对大多是简单场景,在封装基本功能时,考虑到一些特殊场景,没有再进行深度封装了,大家如果有好的、普遍的场景,欢迎大家进行补充
封装步骤
1. 环境搭建
// vue2 环境下
yarn add element-ui
yarn add echarts
2. 全局配置element
// 全局注册 elementUI
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
Vue.use(ElementUI);
3. 封装 @/utils/echarts.js
使用的是按需加载,如果有新的图表,需要在这个文件添加配置
/**
* 作用:按需引入 echarts 减少打包体积,在 NormalEchats 组件中使用
* 说明:根据 官网实例,对比出没有的配置项 进行加入
*
*/
// 1.引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from "echarts/core";
// 2.引入柱状图图表,图表后缀都为 Chart
import { BarChart } from "echarts/charts";
// 3.引入提示框,标题,直角坐标系组件,组件后缀都为 Component
import {
TitleComponent,
TooltipComponent,
GridComponent,
} from "echarts/components";
// 4.引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from "echarts/renderers";
// 注册必须的组件
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
BarChart,
CanvasRenderer,
]);
export default echarts;
封装 BaseEchart.vue 组件
这里的宽高没有用 style 动态传入,我想的是要兼容 rem等 单位的布局,因此视图的宽高由父盒子的大小进行设置
<template>
<div :ref="refName" class="chartBox" />
</template>
<script>
// 引入 配置完成的 echarts
import echarts from "@/utils/echarts";
// 引入默认配置项,
export default {
name: "BaseEchars",
props: {
refName: {
// 图例绑定的dom 一个页面中存在多个图例时不要重复
type: String,
required: true,
},
option: {
// echarts 配置项 直接从官网复制粘贴即可
required: true,
},
},
data() {
return {
chart: null, // echarts 实例
};
},
watch: {
// 监听 echarts 变化 自动更新
option: {
deep: true,
handler() {
console.log("数据变化了,视图更新了");
this.chart.setOption(this.chartOption);
this.$emit("getChart", this.chart);
},
},
},
computed: {
defaultOption() {
//默认配置项 这里的默认配置项 只能兼容 option 第一层级的属性
return {
tooltip: {
trigger: "axis",
axisPointer: {
type: "cross",
label: {
backgroundColor: "#6a7985",
},
},
},
};
},
chartOption() {
// 最终配置项
return { ...this.defaultOption, ...this.option };
},
},
methods: {
// 初始化实例
initChart() {
this.chart = echarts.init(this.$refs[this.refName]);
// 当前配置项 优先级大于 默认配置项
// console.log("当前视图的配置项", this.chartOption);
this.chart.setOption(this.chartOption);
this.$emit("getChart", this.chart);
},
// 自适应
resizeHandler() {
this.chart.resize();
},
},
mounted() {
// 如果传入的 option 为空则不进行初始化
if (!this.option || this.option === "{}") {
return;
}
this.initChart();
window.addEventListener("resize", this.resizeHandler);
},
beforeDestroy() {
if (!this.chart) {
return;
}
window.removeEventListener("resize", this.resizeHandler);
this.chart.dispose();
this.chart = null;
},
};
</script>
<style scoped>
.chartBox {
width: 100%;
height: 100%;
}
</style>
使用 BaseEchart 组件
<template>
<div class="com_box">
<div @click="changeData">改变数据</div>
<BaseEchart refName="baseBar" :option="option" @getChart="getChart" />
</div>
</template>
<script>
export default {
name: "BaseBar",
data() {
return {
xAxisData: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
seriesData: [120, 200, 150, 80, 70, 110, 130],
chart: null,
};
},
computed: {
option() {
// return null;
let barData = {
xAxis: {
type: "category",
data: this.xAxisData,
},
yAxis: {
type: "value",
},
series: [
{
data: this.seriesData,
type: "bar",
},
],
};
return barData;
},
},
methods: {
// 模拟动态数据
changeData() {
this.xAxisData.push("test");
this.seriesData.push(100);
},
// 获取子组件 echarts 的实例
getChart(chart) {
console.log("获取子组件 echarts 的实例", chart);
},
},
};
</script>
<style scoped>
.com_box {
width: 100%;
height: 400px;
/* background-color: red; */
}
</style>