背景介绍
今天在使用echarts绘制一个双图表的数据统计图时候,发现 tooltip 无法显示,经过一番排查,发现是使用上错误导致,如下图所示,鼠标悬浮上不能正确触发tooltip和自定义的 valueFormatter
问题原因
Vue3 底层使用了 proxy 代理创建实例,其创建出来的实例与echarts真正使用的那个存在兼容性问题,所以Echarts 无法从中获取内部变量;故设置echarts实例时,不要使用ref、reactive等响应式方法创建echarts对象,应该使用shallowReactive、shallowRef、或者普通变量即可
示例代码
import {defineComponent, getCurrentInstance, onBeforeUnmount, onMounted, PropType, ref,shallowRef, watch} from 'vue'
import type { Ref } from 'vue'
import * as echarts from "echarts";
import {useI18n} from "vue-i18n";
import {EChartsType} from "echarts/types/dist/echarts";
import {HostBillHistory} from "@/service/budget";
const props = {
height: {
type: [String, Number] as PropType<string | number>,
default: 590
},
width: {
type: [String, Number] as PropType<string | number>,
default: '100%'
},
data: {
type: Array as PropType<Array<HostBillHistory>>
}
}
const HistoryBill = defineComponent({
name: 'HistoryBill',
props,
setup(props) {
const updateChartData = () => {
let dateArr = props.data.map(obj=>obj.day)
let hostArr = props.data.map(obj=>obj.hostCount)
let moneyArr = props.data.map(obj=> parseFloat((obj.money/10000).toFixed(2)))
option.xAxis[0].data=dateArr
option.series[0].data=hostArr
option.series[1].data=moneyArr
}
const option = {
backgroundColor: 'white',
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
crossStyle: {
color: '#999'
}
}
},
toolbox: {
feature: {
dataView: { show: true, readOnly: false },
magicType: { show: true, type: ['line', 'bar'] },
restore: { show: true },
saveAsImage: { show: true }
}
},
legend: {
data: ['主机数量', '账单金额']
},
xAxis: [
{
type: 'category',
data: props.data.map(obj=>obj.day),
axisPointer: {
type: 'shadow'
}
}
],
yAxis: [
{
type: 'value',
name: '主机数量',
min: 0,
max: 250,
interval: 10,
axisLabel: {
formatter: '{value} 台'
}
},
{
type: 'value',
name: '账单金额',
min: 0,
max: 50,
interval: 2,
axisLabel: {
formatter: '{value} 万'
}
}
],
series: [
{
name: '主机数量',
type: 'line',
tooltip: {
valueFormatter: value => value + ' 台'
},
data: props.data.map(obj=>obj.hostCount)
},
{
name: '账单金额',
type: 'bar',
tooltip: {
valueFormatter: value => value + ' 万'
},
yAxisIndex: 1,
data: props.data.map(obj=> parseFloat((obj.money/10000).toFixed(2)))
}
]
}
const globalProperties = getCurrentInstance()?.appContext.config.globalProperties
const billChartRef: Ref<HTMLDivElement | null> = ref(null)
let chart = null // 此处不要使用vue3的响应式方法创建
const init = () => {
chart = globalProperties?.echarts.init(billChartRef.value)
chart.setOption(option)
}
const resize = echarts.throttle(() => {
chart && chart.resize()
}, 20)
watch(
() => props.data,
() => {
// option.series[0].data= top10()
updateChartData()
chart.setOption(option)
}
)
onMounted(() => {
init()
addEventListener('resize', resize)
})
return { billChartRef }
},
render() {
const { height, width } = this
return (
<div
ref='billChartRef'
id={'myChart'}
style={{
height: "100%",
width: typeof width === 'number' ? width + 'px' : width
}}
>
</div>
)
}
})
export default HistoryBill