Vue
组件
<template>
<div :style="{ height: height, width: width }" :class="className" :id="id">div>
template>
<script>
window._CHARTLIST_ = [];
import * as echarts from "echarts";
import { debounce } from "./lodash-util";
export default {
props: {
id: {
type: String,
required: true,
},
className: {
type: String,
default: "chart",
},
width: {
type: String,
default: "100%",
},
height: {
type: String,
default: "100%",
},
options: {
type: Object,
required: true,
default: () => ({}),
},
},
data() {
return {
chart: null,
};
},
methods: {
initChart() {
if (!this.chart) {
const chartDom = document.querySelector(`#${this.id}`);
this.chart = echarts.init(chartDom);
this.chart.setOption(this.options, true);
window._CHARTLIST_.push(this.chart);
window.addEventListener("resize", this.resize);
} else {
this.chart.setOption(this.options, true);
this.chart.resize();
}
},
resize() {
const { chartObj } = this;
const resizeFunc = function () {
if (window._CHARTLIST_ && Array.isArray(_CHARTLIST_)) {
window._CHARTLIST_.forEach((item) => {
item.resize && item.resize();
});
}
};
debounce(resizeFunc, 300);
},
},
mounted: function () {
this.initChart();
},
beforeDestroy() {
if (this.chart) {
if (window._CHARTLIST_ && Array.isArray(_CHARTLIST_)) {
window._CHARTLIST_.forEach((item, index) => {
item.id === this.chart.id && window._CHARTLIST_.splice(index, 1);
});
}
this.chart = null;
window.removeEventListener("resize", this.resize);
}
},
watch: {
options: {
handler(n) {
if (Object.keys(n).length > 0) {
this.initChart();
}
},
deep: true,
},
},
};
script>
React
组件
import React, { memo } from 'react';
import * as echarts from 'echarts/core';
import { ECharts } from 'echarts/types/dist/core';
import { EChartsOption } from 'echarts/types/dist/shared';
import {
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
DatasetComponent,
DataZoomComponent,
ToolboxComponent,
} from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';
import { debounce, forEach } from 'lodash';
type domClassName = string[];
interface IEchartProps {
option: EChartsOption;
domClassName?: domClassName;
charts?: any[];
}
interface IEchartState {
chart: null | ECharts;
domClassName: domClassName;
}
class Echart extends React.Component<IEchartProps, IEchartState> {
constructor(props: IEchartProps) {
super(props);
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
DatasetComponent,
CanvasRenderer,
DataZoomComponent,
ToolboxComponent,
...(props.charts || []),
]);
this.state = { chart: null, domClassName: ['.collapse', '.header-collapse', ...(props.domClassName || [])] };
}
chartRef = React.createRef<HTMLDivElement>();
componentDidMount() {
this.initChart();
this.btnListenResizeEvent('add');
window.addEventListener('resize', this.resize);
}
componentDidUpdate(): void {
const { option: newOptions } = this.props;
const { chart } = this.state;
if (newOptions && chart) chart.setOption(newOptions, true);
}
componentWillUnmount() {
const { chart } = this.state;
if (chart) chart.dispose();
this.btnListenResizeEvent('remove');
window.removeEventListener('resize', this.resize);
}
initChart = debounce(() => {
if (!this.chartRef.current) return;
this.setState({ chart: echarts.init(this.chartRef.current) });
}, 200);
resize = debounce(() => this.state.chart?.resize(), 200);
btnListenResizeEvent = debounce((type: 'add' | 'remove') => {
forEach(this.state.domClassName, (v) => {
if (type === 'add') {
document.querySelector(v)?.addEventListener('click', this.resize);
} else {
document.querySelector(v)?.removeEventListener('click', this.resize);
}
});
}, 200);
render(): React.ReactNode {
return <div style={{ height: '100%' }} ref={this.chartRef} />;
}
}
export default memo(Echart);
import Echart from '@/components/Echarts';
import { LineChart } from 'echarts/charts';
function Demo(){
const options = { } ;
return (<Echart option={options} charts={[LineChart]} />);
}