問題介紹
使用Echarts在Vue3+Vite項目中繪制堆疊折線圖的的時候,tooltip總是不顯示,經過很長時間的排查和修改,最后發現是在使用上有錯誤導致的。
錯誤圖片展示
問題原因
由于Vue3底層使用proxy代理創建示例,使用其創建出來的實例與Echarts真正使用的的實例存在兼容性問題,所以Echarts無法從中獲取內部變量,所以在使用Echarts實例的時候,不要使用ref或reactive等響應式方法創建Echarts對象,應該使用shallowReactive、shallowRef或者普通變量。
導致問題代碼
const chartInstance3 = ref(null); //定義店鋪入駐明細圖表實例化
const chartContainer3 = ref();
shallowReactive、shallowRef與reactive、ref的區別
API | 介紹 |
---|---|
reactive |
|
shallowReactive |
|
ref |
|
shallowRef |
|
總結:
reactive
和ref
都提供深度響應性,但ref
還提供了一層額外的封裝。shallowReactive
和shallowRef
僅提供一層響應性,這對于性能敏感的應用或不需要深度響應性的數據結構很有用。
修改后的實現效果
修改后的代碼
const chartInstance3 = shallowRef(null); //定義店鋪入駐明細圖表實例化
const chartContainer3 = shallowRef();
附完整代碼
<template><divref="chartContainer3"style="width: 100%; height: 400px; margin-top: 20px"></div>
</template><script setup>
import * as echarts from "echarts";
import { onMounted, onUnmounted, ref, shallowRef } from "vue";
import request from "@/utils/request";
import api from "@/api";
import formatTime from "@/utils/formatTime";
const chartInstance3 = shallowRef(null); //定義店鋪入駐明細圖表實例化
const chartContainer3 = shallowRef();const ServiceCategoryList = ref([]); //店鋪類別列表
// 獲取所有店鋪類別
const getShopCategory = async () => {const res = await request.get(api.getShopCategory);res.data.forEach((item) => {ServiceCategoryList.value.push({name: item.name,type: "line", //圖標的類型,line:折線圖// stack: "total",shopType: item.type,smooth: "true",data: [],});});
};
const shopList = ref([]); //入駐店鋪列表
const startTime = ref(""); //入住店鋪最早的創建時間
const endTime = new Date(); //當前時間
const dateArray = ref([]); //日期數組
// 創建時間列表
const createTimeList = (start, end) => {while (start <= end) {dateArray.value.push(start.toISOString().substring(0, 10)); // 只保留YYYY-MM-DD格式start.setDate(start.getDate() + 1); // 增加一天}
};
// 獲取入駐平臺的所有店鋪
const getShopList = async () => {await request.get(api.shopList).then((res) => {res.data.forEach((item) => {item.createTime = formatTime(item.createTime).nohour;item.createTimeObj = new Date(item.createTime);shopList.value.push({shopName: item.shopName,createTime: item.createTime,shopType: item.shopType,});});// 使用sort方法對shopList按創建時間排序,并找出最早入駐的時間res.data.sort((a, b) => a.createTimeObj - b.createTimeObj);startTime.value = new Date(res.data[0].createTime);createTimeList(startTime.value, endTime); //生成時間列表// 將所有的店鋪按照店鋪類別進行分組const shopsGroupedByTypeAndTime = res.data.reduce((groups, shop) => {const shopType = shop.shopType;const shopTime = shop.createTime;// 如果還沒有對應店鋪類型的分組,則創建它if (!groups[shopType]) {groups[shopType] = {};}// 如果還沒有對應時間的分組,則創建它if (!groups[shopType][shopTime]) {groups[shopType][shopTime] = 0;}// 將對應時間和類型的計數增加1groups[shopType][shopTime]++;return groups;}, {});ServiceCategoryList.value.forEach((item) => {if (shopsGroupedByTypeAndTime[item.shopType]) {item.data = shopsGroupedByTypeAndTime[item.shopType];}dateArray.value.forEach((date) => {if (!item.data[date]) {item.data[date] = 0;}});item.data = Object.entries(item.data).sort(([keyA], [keyB]) => new Date(keyA) - new Date(keyB)).map(([key, value]) => value);});});
};
const setOptions3 = () => {chartInstance3.value.setOption({title: {text: "商家入駐數據明細",},tooltip: {trigger: "axis",axisPointer: {type: "cross",},},legend: {data: ServiceCategoryList.value.map((item) => item.name),},grid: {left: "3%",right: "4%",bottom: "3%",containLabel: true,},xAxis: {type: "category",boundaryGap: false,data: dateArray.value,},yAxis: {type: "value",},series: [...ServiceCategoryList.value],});
};
onMounted(async () => {await getShopCategory();await getShopList();chartInstance3.value = echarts.init(chartContainer3.value);setOptions3();
});
onUnmounted(() => {// 組件卸載時銷毀圖表實例chartInstance3.value.dispose();
});
</script>