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);

我想要的很简单,时光还在,你还在

Logo

前往低代码交流专区

更多推荐