vue 一个组件中一个或者多个动态echarts图表切换渲染问题
vue 一个组件中一个或者多个动态echarts图表切换渲染问题;echarts.js:2286 Can't get DOM width or height. Please check dom.clientWidth and dom.clientHeight. They should not be 0.For example, you may need to call this in the ca
·
1、项目中经常遇到,切换tab数据时,展示不一样的图表,一个图表切换,在循环tab里echarts的id盒子加上动态id
<a-spin :spinning="loading">
<div class="chart-box" >
<div :id="'echartBox' + item.id" class="echartBox" v-if="state.tabList.length"></div>
<a-empty v-else />
</div>
</a-spin>
const initCharts = () => {
nextTick(() => {
if(!myChart) {
} else {
myChart.dispose();
}
myChart = echarts.init(document.getElementById(`echartBox${activeKey.value}`));
if(myChart) {
option && myChart.setOption(option);
}
});
}
2、完整代码
<template>
<div class="work-info">
<a-tabs v-model:activeKey="activeKey" @change="changeTab">
<a-tab-pane :tab="item.deviceCode" v-for="item in state.codeList" :key="item.id">
<div class="center-box">
<div class="select-item" v-if="state.tabList.length">
<span>监测项:</span>
<a-select
v-model:value="termActive"
style="width: 120px"
@select="termChange"
>
<a-select-option :value="index" v-for="(item, index) in state.tabList" :key="index">{{ item.name }}</a-select-option>
</a-select>
</div>
<div class="number-box">
<ul class="number-ul">
<li class="number-item">
<span>
最高:
</span>
<span>
{{ high || '--'}}
</span>
</li>
<li class="number-item">
<span class="work-txt">
最低:
</span>
<span>
{{ low || '--'}}
</span>
</li>
<li class="number-item">
<span class="work-txt">
平均:
</span>
<span>
{{ avg || '--'}}
</span>
</li>
</ul>
</div>
</div>
<div class="alarm-tab">
<ul class="alarm-tab-ul">
<li class="alarm-item" v-for="item in state.timeList" :key="item.id" @click="changeTime(item.id)" :class="{'active': activeTab == item.id}">
{{ item.name }}
</li>
</ul>
</div>
<a-spin :spinning="loading">
<div class="chart-box" >
<div :id="'echartBox' + item.id" class="echartBox" v-if="state.tabList.length"></div>
<a-empty v-else />
</div>
</a-spin>
</a-tab-pane>
</a-tabs>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, nextTick, inject } from "vue";
import * as echarts from 'echarts';
import {request} from '@/utils/request.js';
const url = inject("url");
let loading = ref(false);
let xData = ref([]);
let yData = ref([]);
const props = defineProps({
siteId:{
type: Number,
default: 0
}
})
const state = reactive({
codeList: [],
tabList: [],
timeList: [
{
id: 1,
name: '当天'
},
{
id: 2,
name: '三天'
},
{
id: 3,
name: '七天'
},
{
id: 4,
name: '近一月'
},
{
id: 5,
name: '近一年'
},
],
})
let option = {
// color: ["#fff"],
title: {
text: "",
textStyle: {
fontSize: '14px'
},
padding: [5,5,5,20]
},
tooltip: {
trigger: "axis",
show: true,
backgroundColor: "#0e163a", //背景颜色
borderRadius: 8, //边框圆角
padding: 5, // [5, 10, 15, 20] 内边距
textStyle: {
color: "#fff",
},
axisPointer: {
type: 'cross',
z: 15,
label: {
show: true,
color: '#fff'
}
}
},
grid: {
top: "15%",
left: "1%",
right: "5%",
bottom: "2%",
containLabel: true,
},
xAxis: [
{
type: "category",
// gridIndex: 0,
boundaryGap: true,
alignWithLabel: true,
// data: this.xData, // x轴数据
splitNumber: 5,
minInterval: 1,
nameTextStyle: {
width: 10,
},
// inverse: true, // 倒过来显示,先从x轴最右边显示
axisLabel: {
showMaxLabel: true,
// formatter: '{value}',
formatter: function (value) {
// 横轴文字显示换行回调
var newParamsName = "";
var paramsNameNumber = value.length;
var provideNumber = 11; // 一行显示几个字
var rowNumber = Math.ceil(paramsNameNumber / provideNumber);
if (paramsNameNumber > provideNumber) {
for (var p = 0; p < rowNumber; p++) {
var tempStr = "";
var start = p * provideNumber;
var end = start + provideNumber;
if (p == rowNumber - 1) {
tempStr = value.substring(start, paramsNameNumber);
} else {
tempStr = value.substring(start, end) + "\n";
}
newParamsName += tempStr;
}
} else {
newParamsName = value;
}
return newParamsName;
},
// textStyle: {
// color: "#fff",
// },
// interval: this.termActive == "1" ? 800 : this.termActive == "2" ? 1100 : this.termActive == "3" ? 1500 : this.termActive == "4" ? 2000 : 3000// 刻度间隔100条数据
},
},
],
yAxis: [
{
type: "value",
splitLine: {
lineStyle: {
type: "dashed",
},
},
axisLabel: {
formatter: "{value}",
// textStyle: {
// color: "#fff",
// },
},
},
],
dataZoom: [
{
type: 'inside',
start: 65,
end: 85
}
],
series: [
{
// name: this.tabName, // 鼠标点击展示的数据标题
type: "line",
stack: "",
smooth: true,
lineStyle: {
width: 2,
// color: "#fff",
},
showSymbol: false,
emphasis: {
focus: "series",
},
// data: this.yData // 值
},
],
};
let myChart = null;
let activeKey = ref(-1);
let termActive = ref(0);
let activeTab = ref(1);
let tabName = ref("");
let dataArr = ref([]);
let high = ref(0);
let low = ref(0);
let avg = ref(0);
let siteId = ref(-1);
const changeTab = (tab) => {
activeKey.value = tab;
termActive.value = 0;
activeTab.value = 1;
getData(activeKey.value, 0, 1);
};
const termChange = (index) => {
termActive.value = index;
getTabData(termActive.value);
};
// 切换
const changeTime = (tab) => {
activeTab.value = tab;
termActive.value = 0;
if(activeKey.value == -1) {
getData(siteId.value, termActive.value, tab);
} else {
getData(activeKey.value, termActive.value, tab);
}
};
// 封装切换tab方法
const getTabData = (tab) => {
tabName.value = state.tabList[tab].unit;
dataArr.value = state.tabList[tab];
high.value = state.tabList[tab].high;
low.value = state.tabList[tab].low;
avg.value = state.tabList[tab].avg;
// 进来就先清空,不然数据会重叠push
xData.value = [];
yData.value = [];
// 无数据
if (dataArr.value.length == 0) {
high.value = "";
low.value = "";
avg.value = "";
} else {
// 当天,显示24小时消失
dataArr.value.data.forEach((item) => {
// 值
xData.value.push(item.testTime);
yData.value.push(item.dataVal);
});
xData.value = xData.value.length > 0 ? xData.value : [];
yData.value = yData.value.length > 0 ? yData.value : [];
}
option.xAxis[0].data = xData.value;
option.series[0].data = yData.value;
option.title.text = tabName.value;
initCharts();
};
//获取分析数据 this.siteInfo.id
const getData = async(id, tab, fast) => {
let newUrl;
// 判断如果操作了编码筛选,则使用编码的id请求(测站id只用于初始化)
if (activeKey.value != -1) {
newUrl = url.GET_HOME_WORK_INFO_BY_DEVICEID;
} else {
siteId.value = id; // 存起来
newUrl = url.GET_HOME_WORK_INFO_BY_SITEID;
}
loading.value = true;
request(newUrl,'get', {
id,
fast
})
.then(res=>{
loading.value = false;
// this.deviceCode = res.data.data.chart.stationCode; // 设备编码
if (activeKey.value == -1) {
state.codeList = res.device; // 设备编码tab
// 默认选中第一项
activeKey.value = state.codeList.length ? state.codeList[0].id : "";
}
state.tabList =
res.chart.stationChartVos &&
res.chart.stationChartVos.length > 0
? res.chart.stationChartVos
: [];
// 当前tab下的对象数据
if (state.tabList.length > 0) {
getTabData(tab);
} else {
state.tabList = [];
dataArr.value = {};
high.value = 0;
low.value = 0;
avg.value = 0;
}
})
.catch(() => {
loading.value = false;
})
};
const initCharts = () => {
nextTick(() => {
if(!myChart) {
} else {
myChart.dispose();
}
myChart = echarts.init(document.getElementById(`echartBox${activeKey.value}`));
if(myChart) {
option && myChart.setOption(option);
}
});
}
onMounted(() => {
getData(props.siteId, 0, 1);
})
3、两个图表
<a-spin :spinning="loading">
<div class="chart-box">
<span class="average-txt average-color"> {{ timeAverage }}平均值:{{ state.listData.length > 1? waterAvg : '0' }}mm <MinusOutlined v-if="waterAvg - waterBf == 0" class="minus" /> <ArrowUpOutlined v-if="waterAvg - waterBf > 0" class="arrow-up" /><ArrowDownOutlined v-if="waterAvg - waterBf < 0" class="arrow-down" />
</span>
<div class="compare">
<span class="p-num">{{ waterBf }}</span>
<span class="tip" v-show="waterBf">比去年同期</span>
</div>
<div :id="'echartBox_top' + item.deviceId + i.id" class="echartBox_top" v-if="state.listData.length > 1"></div>
<a-empty v-else />
</div>
</a-spin>
<a-spin :spinning="waterLoading">
<div class="chart-box">
<div class="all-box">
<span class="average-txt all-color"> {{ timeAverage }}降雨总量:{{ rainSum || '0' }}mm <MinusOutlined v-if="rainSum - rainSumBf == 0" class="minus" /> <ArrowUpOutlined v-if="rainSum - rainSumBf > 0" class="arrow-up" /><ArrowDownOutlined v-if="rainSum - rainSumBf < 0" class="arrow-down" />
</span>
<div class="compare">
<span class="p-num">{{ rainSumBf }}</span>
<span class="tip" v-show="rainSumBf">比去年同期</span>
</div>
</div>
<div :id="'echartBox_bm' + item.deviceId + i.id" class="echartBox_bm" v-if="state.rainData.length > 1"></div>
<a-empty v-else />
</div>
</a-spin>
const initCharts = () => {
if(!myChart) {
} else {
myChart.dispose()
}
if(!myAllChart) {
} else {
myAllChart.dispose()
}
myChart = echarts.init(document.getElementById(`echartBox_top${activeKey.value}${activeTime.value}`));
if(options && myChart) {
myChart.setOption(options);
}
myAllChart = echarts.init(document.getElementById(`echartBox_bm${activeKey.value}${activeTime.value}`));
if(rainOption && myAllChart) {
myAllChart.setOption(rainOption);
}
}
4、完整代码
<template>
<div class="analysis-info">
<a-tabs v-model:activeKey="activeKey" @change="changeTab">
<a-tab-pane :tab="item.deviceCode" v-for="item in state.tabList" :key="item.deviceId">
<a-tabs v-model:activeKey="activeTime" @change="changeTimeTab">
<a-tab-pane :tab="i.name" v-for="i in state.tabTimeList" :key="i.id">
<a-spin :spinning="loading">
<div class="chart-box">
<span class="average-txt average-color"> {{ timeAverage }}平均值:{{ state.listData.length > 1? waterAvg : '0' }}mm <MinusOutlined v-if="waterAvg - waterBf == 0" class="minus" /> <ArrowUpOutlined v-if="waterAvg - waterBf > 0" class="arrow-up" /><ArrowDownOutlined v-if="waterAvg - waterBf < 0" class="arrow-down" />
</span>
<div class="compare">
<span class="p-num">{{ waterBf }}</span>
<span class="tip" v-show="waterBf">比去年同期</span>
</div>
<div :id="'echartBox_top' + item.deviceId + i.id" class="echartBox_top" v-if="state.listData.length > 1"></div>
<a-empty v-else />
</div>
</a-spin>
<a-spin :spinning="waterLoading">
<div class="chart-box">
<div class="all-box">
<span class="average-txt all-color"> {{ timeAverage }}降雨总量:{{ rainSum || '0' }}mm <MinusOutlined v-if="rainSum - rainSumBf == 0" class="minus" /> <ArrowUpOutlined v-if="rainSum - rainSumBf > 0" class="arrow-up" /><ArrowDownOutlined v-if="rainSum - rainSumBf < 0" class="arrow-down" />
</span>
<div class="compare">
<span class="p-num">{{ rainSumBf }}</span>
<span class="tip" v-show="rainSumBf">比去年同期</span>
</div>
</div>
<div :id="'echartBox_bm' + item.deviceId + i.id" class="echartBox_bm" v-if="state.rainData.length > 1"></div>
<a-empty v-else />
</div>
</a-spin>
</a-tab-pane>
</a-tabs>
</a-tab-pane>
</a-tabs>
</div>
</template>
<script setup>
import { ArrowUpOutlined, ArrowDownOutlined, MinusOutlined } from '@ant-design/icons-vue';
import { ref, reactive, onMounted, nextTick, inject } from "vue";
import * as echarts from 'echarts';
import {request} from '@/utils/request.js';
const url = inject("url");
let loading = ref(false);
let waterLoading = ref(false);
const props = defineProps({
siteId:{
type: Number,
default: 0
}
})
const state = reactive({
tabList: [],
tabTimeList: [
{
id: 1,
name: '当天'
},
{
id: 2,
name: '近一月'
},
{
id: 3,
name: '近一年'
}
],
listData: [],
rainData: []
})
let options = {
xAxis: {
type: "category",
boundaryGap: false,
show: false,
},
yAxis: {
type: "value",
show: false,
},
color: ["#1583FF"],
tooltip: {
trigger: "axis",
show: true,
backgroundColor: "#0e163a", //背景颜色
borderRadius: 8, //边框圆角
padding: 5, // [5, 10, 15, 20] 内边距
textStyle: {
color: "#fff",
},
axisPointer: {
type: 'cross',
z: 15,
label: {
show: true,
color: '#fff'
}
}
},
grid: {
left: 0,
right: "1%",
bottom: 0,
top: "2%",
containLabel: true,
},
dataZoom: {
type: "inside",
show: true,
start: 0,
end: 100,
},
series: [
{
type: "line",
smooth: true,
showSymbol: false,
areaStyle: {
opacity: 0.8,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "rgba(137, 192, 255)",
},
{
offset: 1,
color: "rgba(245, 250, 255)",
},
]),
},
},
],
};
let rainOption = {
xAxis: {
type: "category",
boundaryGap: false,
show: false,
},
yAxis: {
type: "value",
show: false,
},
color: ["#1583FF"],
tooltip: {
trigger: "axis",
show: true,
backgroundColor: "#0e163a", //背景颜色
borderRadius: 8, //边框圆角
padding: 5, // [5, 10, 15, 20] 内边距
textStyle: {
color: "#fff",
},
axisPointer: {
type: 'cross',
z: 15,
label: {
show: true,
color: '#fff'
}
}
},
grid: {
left: 0,
right: "1%",
bottom: 0,
top: "2%",
containLabel: true,
},
dataZoom: {
type: "inside",
show: true,
start: 0,
end: 100,
},
series: [
{
type: "line",
smooth: true,
showSymbol: false,
areaStyle: {
opacity: 0.8,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "rgba(137, 192, 255)",
},
{
offset: 1,
color: "rgba(245, 250, 255)",
},
]),
},
},
],
};
let myChart = null;
let myAllChart = null;
let activeKey = ref(-1);
let activeTime = ref(1);
let timeAverage = ref('日');
let waterAvg = ref("");
let waterBf = ref("");
let rainSum = ref(0);
let rainSumBf = ref(0);
const changeTab = (tab) => {
activeKey.value = tab;
activeTime.value = 1;
getData(activeKey.value);
};
const changeTimeTab = (tab) => {
activeTime.value = tab;
switch (tab) {
case 1:
timeAverage.value = '日'
break;
case 2:
timeAverage.value = '月'
break;
default:
timeAverage.value = '年'
break;
}
getData(activeKey.value);
};
const getData = async(id) => {
loading.value = true;
waterLoading.value = true;
request(url.GET_HOME_ANALYSIS_DATA,'get', {
deviceId: id,
dateType: activeTime.value
})
.then(data=>{
loading.value = false;
waterLoading.value = false;
waterAvg.value = data.water.avg ? data.water.avg.toFixed(3) : "";
waterBf.value = data.water.beforeAvg
? data.water.beforeAvg.toFixed(3)
: "";
rainSum.value = data.rain.sum ? data.rain.sum.toFixed(3) : "";
rainSumBf.value = data.rain.beforeSum
? data.rain.beforeSum.toFixed(3)
: "";
state.listData = data.water.reportLabelDataList;
state.rainData = data.rain.rainStPpntRList;
if (state.rainData.length || state.listData.length) {
let xData = state.listData.map((i) => i.tm);
let yData = state.listData.map((i) => i.waterLevel);
let rXData = state.rainData.map((i) => i.TM);
let rYData = state.rainData.map((i) => i.VAL);
options.xAxis.data = xData;
options.series[0].data = yData;
rainOption.xAxis.data = rXData;
rainOption.series[0].data = rYData;
initCharts();
}
})
.catch(() => {
loading.value = false;
waterLoading.value = false;
})
};
// 获取设备列表
const getDeviceInfo = (id) => {
request(url.GET_DEVICE_INFO_BY_STATION_ID,'get', {
stationId: id
})
.then(res => {
state.tabList = res;
if(state.tabList.length) {
activeKey.value = state.tabList[0].deviceId;
getData(activeKey.value);
}
})
};
const initCharts = () => {
if(!myChart) {
} else {
myChart.dispose()
}
if(!myAllChart) {
} else {
myAllChart.dispose()
}
myChart = echarts.init(document.getElementById(`echartBox_top${activeKey.value}${activeTime.value}`));
if(options && myChart) {
myChart.setOption(options);
}
myAllChart = echarts.init(document.getElementById(`echartBox_bm${activeKey.value}${activeTime.value}`));
if(rainOption && myAllChart) {
myAllChart.setOption(rainOption);
}
}
onMounted(() => {
getDeviceInfo(props.siteId);
})
</script>
5、但是发现渲染不出来,控制台发出了提示:未获取dom的宽高就渲染了
6、而且使用v-if去控制渲染,会遇到这样的警告,也是未获取到dom就去渲染了
7、解决,改成v-show去控制,且在调用实例echarts加了延迟触发,至于浏览器的提示信息:Can’t get DOM width or height. Please check dom.clientWidth and dom.clientHeight. They should not be 0.For example, you may need to call this in the callback of window.onload. 选择忽视,又不是不能用,哈哈哈哈
<a-spin :spinning="loading">
<div class="chart-box">
<span class="average-txt average-color"> {{ timeAverage }}平均值:{{ state.listData.length > 1? waterAvg : '0' }}mm <MinusOutlined v-if="waterAvg - waterBf == 0" class="minus" /> <ArrowUpOutlined v-if="waterAvg - waterBf > 0" class="arrow-up" /><ArrowDownOutlined v-if="waterAvg - waterBf < 0" class="arrow-down" />
</span>
<div class="compare">
<span class="p-num">{{ waterBf }}</span>
<span class="tip" v-show="waterBf">比去年同期</span>
</div>
<div :id="'echartBox_top' + item.deviceId + i.id" class="echartBox_top" v-show="state.listData.length > 1"></div>
<a-empty v-show="state.listData.length <=1 " />
</div>
</a-spin>
setTimeout(() => {
initCharts();
}, 500);
我想要的很简单,时光还在,你还在
更多推荐
已为社区贡献35条内容
所有评论(0)