使用echarts
使用echarts主要有两个痛点:
- echarts如果使用全量加载,打包后的体积会比较大,为了减小打包后的体积,我们使用按需引入的方式。
- 我们在做echarts图表的时候,其实只希望传入option属性即可,浏览器resize需要对样式做实时的调整,以及销毁监听事件等,我们希望放在一个公共的hooks中。
依赖注入echarts模块
ts
import * as echarts from 'echarts/core'
// 引入柱状图和饼状图图表,图表后缀都为 Chart,具体为 图标名称+Chart (注意图表名称为首字母大写)
import { BarChart, CustomChart, LineChart, PictorialBarChart } from 'echarts/charts'
// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
import { GridComponent, LegendComponent, TitleComponent, TooltipComponent } from 'echarts/components'
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { SVGRenderer } from 'echarts/renderers'
echarts.use([
BarChart,
LineChart,
PictorialBarChart,
CustomChart,
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
SVGRenderer
])
export default echartsuseEcharts 函数
ts
import { useTimeoutFn } from '@dt-frames/core'
import { useMenu } from '@dt-frames/ui'
import { tryOnUnmounted } from '@vueuse/core'
import type { EChartsOption } from 'echarts'
import { Ref } from 'vue'
import echarts from './echarts'
interface Fn<T = any, R = T> {
(...arg: T[]): R
}
/**
* @param elRef 绑定的dom实例
* @param theme 图表将使用的主题
*/
export function useEcharts(elRef: Ref<HTMLDivElement>, theme: 'light' | 'dark' = 'dark') {
const resizeFn: Fn = resize
// 获取已经缓存的配置信息 用于重新渲染
const cacheOptions = ref({}) as Ref<EChartsOption>
const getOptions = computed(() => {
if (theme !== 'dark') {
return cacheOptions.value as EChartsOption
}
return {
backgroundColor: 'transparent',
...cacheOptions.value
} as EChartsOption
})
// 初始化echarts
let chartInstance: echarts.ECharts | null = null
let removeResizeFn: Fn = () => {}
function initCharts() {
const el = unref(elRef)
if (!el || !unref(el)) {
error('未找到元素!')
return
}
chartInstance = echarts.init(el, theme)
// 停止resize事件
removeResizeFn()
const [start, stop] = windowResize(resizeFn, 100)
start()
removeResizeFn = stop
}
// 设置配置信息
function setOptions(options: EChartsOption, clear = true) {
cacheOptions.value = options
return new Promise(resolve => {
nextTick(() => {
useTimeoutFn(() => {
if (!chartInstance) {
initCharts()
if (!chartInstance) return
}
clear && chartInstance?.clear()
chartInstance?.setOption(unref(getOptions))
resolve(null)
}, 30)
})
})
}
function resize() {
chartInstance?.resize({
animation: {
duration: 300,
easing: 'quadraticIn'
}
})
}
// 左侧菜单折叠后重新渲染
const { getCollapsed } = useMenu()
watch(getCollapsed, () => {
useTimeoutFn(() => {
resizeFn()
}, 300)
})
// 获取echart实例
function getInstance() {
if (!chartInstance) {
initCharts()
}
return chartInstance
}
// 销毁实例及window resize监听
tryOnUnmounted(() => {
if (!chartInstance) return
removeResizeFn()
chartInstance.dispose()
chartInstance = null
})
return {
setOptions,
resize,
echarts,
getInstance
}
}页面使用
ts
<!-- html -->
<div ref="elRef"></div>
// script
const elRef = ref(null)
const { setOptions } = useEcharts(elRef)
onMounted(() => {
setOptions({
xAxis: {
// ...
},
grid: {
// ...
}
})
})