Solve the problem of vue3+echarts about being unable to obtain the dom width and height

Solve the problem of vue3+echarts about being unable to obtain the dom width and height

Recently, when I was writing a vue3 project, echarts was used in many places. When I first started writing, I found that the picture never came out, and the error/alarm content usually included two items:

  • Uncaught (in promise) Error: Initialize failed: invalid dom.
  • vue3 [ECharts] Can’t get DOM width or height.

Explain these two error reports respectively.

The first error is that when initializing echarts, the corresponding dom element was not found, so it is necessary to initialize the echarts diagram after the dom element is rendered.

The second error is that the width or height of the dom corresponding to echarts cannot be obtained. This problem usually occurs when setting the width and height of the dom node. The percentage form is used. The width and height of ECharts are in pixels by default, which cannot be Set directly using percentages

After many attempts, I finally solved this problem. Record the solution.

First the code:

<template>
  <div class="right">
    <div class="top">
      <div class="top-left" ref="topLeft"></div>
      <div class="top-right" ref="topRight"></div>
    </div>
    <div class="middle" ref="middle"></div>
    <div class="bottom">
      <div class="bottom-left" ref="bottomLeft"></div>
      <div class="bottom-right" ref="bottomRight"></div>
    </div>
  </div>
</template>

<script setup>
import * as echarts from "echarts";
import {
    
     ref, onMounted } from 'vue'
import {
    
     driverAgeLT, driverAgeRT, driverAgeMiddle, driverAgeBL, driverAgeBR } from './graphOptions.js'

const topLeft = ref(null)
const LTOptions = driverAgeLT()
const drawLTchart = () => {
    
    
  const topLeftChart = echarts.init(topLeft.value)
  topLeftChart.setOption(LTOptions)
  topLeftChart.resize()
  window.addEventListener('resize', () => {
    
    
    topLeftChart.resize()
  })
}

const topRight = ref(null)
const RTOptions = driverAgeRT()
const drawRTchart = () => {
    
    
  const topRightChart = echarts.init(topRight.value)
  topRightChart.setOption(RTOptions)
  topRightChart.resize()
  window.addEventListener('resize', () => {
    
    
    topRightChart.resize()
  })
}

const middle = ref(null)
const middleOptions = driverAgeMiddle()
const drawMiddleChart = () => {
    
    
  const midddleChart = echarts.init(middle.value)
  midddleChart.setOption(middleOptions)
  midddleChart.resize()
  window.addEventListener('resize', () => {
    
    
    midddleChart.resize()
  })
}

const bottomLeft = ref(null)
const BLOptions = driverAgeBL()
const drawBLchart = () => {
    
    
  const bottomLeftChart = echarts.init(bottomLeft.value)
  bottomLeftChart.setOption(BLOptions)
  bottomLeftChart.resize()
  window.addEventListener('resize', () => {
    
    
    bottomLeftChart.resize()
  })
}

const bottomRight = ref(null)
const BROptions = driverAgeBR()
const drawBRchart = () => {
    
    
  const bottomRightChart = echarts.init(bottomRight.value)
  bottomRightChart.setOption(BROptions)
  bottomRightChart.resize()
  window.addEventListener('resize', () => {
    
    
    bottomRightChart.resize()
  })
}

onMounted(() => {
    
    
  setTimeout(() => {
    
    
    drawLTchart()
    drawRTchart()
    drawMiddleChart()
    drawBLchart()
    drawBRchart()
  }, 200)
})
</script>

<style lang="scss" scoped>
.right {
    
    
  width: 49%;
  margin-left: 10px;
  height: 99%;
  display: flex;
  flex-direction: column;
  padding: 10px;
  box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px, rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;

  .top {
    
    
    height: 33%;
    display: flex;
    box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 0px 1px, rgb(209, 213, 219) 0px 0px 0px 1px inset;

    .top-left {
    
    
      width: 50%;
      padding: 5px;
      height: 100%;
      border-right: 1px dashed #ccc;
    }

    .top-right {
    
    
      width: 50%;
      padding: 5px;
      height: 100%;
    }
  }

  .middle {
    
    
    margin-top: 5px;
    height: 33%;
    padding: 5px;
    width: 100%;
    box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 0px 1px, rgb(209, 213, 219) 0px 0px 0px 1px inset;
  }

  .bottom {
    
    
    height: 33%;
    margin-top: 5px;
    display: flex;
    box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 0px 1px, rgb(209, 213, 219) 0px 0px 0px 1px inset;

    .bottom-left {
    
    
      width: 50%;
      padding: 5px;
      height: 100%;
      border-right: 1px dashed #ccc;
    }

    .bottom-right {
    
    
      width: 50%;
      padding: 5px;
      height: 100%;
    }
  }
}
</style>

Effect
Insert image description here

I only put the picture part of the code. The function of the code is to draw 5 pictures on the right side of the page. As you can see from the style I wrote, I used percentages for all the DOM drawing pictures. This has an advantage, no matter what The screen can be displayed relatively well, but echarts does not support percentage width and height, so the alarm is raised

Next, explain the code:

  • import { driverAgeLT, driverAgeRT, driverAgeMiddle, driverAgeBL, driverAgeBR } from './graphOptions.js'This line of code means that I put the options of the five pictures into a js file. It is also a manifestation of component-based development. I will not put this file. You can set it yourself how you want to draw the picture.

  • The following lines of code are the key. I will explain them directly in the form of comments.

    const topLeft = ref(null)  // 获取dom
    const LTOptions = driverAgeLT()  // 获取对应的options
    const drawLTchart = () => {
          
            // 画图函数,为啥要写成函数,因为需要在页面加载完成后调用,要放在生命周期函数中
      const topLeftChart = echarts.init(topLeft.value)  // 初始化echarts图,注意,这里的topLeft是响应式的dom,必须要加value,这里我经常忘记
      topLeftChart.setOption(LTOptions)  // 设置option
      topLeftChart.resize()  // 这里也比较关键,在option后,最好是重绘一下图,可以解决百分比宽高的问题,也就是解决第2个问题
      window.addEventListener('resize', () => {
          
            // 窗口大小变化后,重绘图
        topLeftChart.resize()
      })
    }
    
    onMounted(() => {
          
            // vue3的生命周期函数,在页面加载完成后,再画图,其实就是解决第1个问题
      setTimeout(() => {
          
            // 这里为啥要用定时器在0.2s后再画图呢,其实我也不能确定是不是这个问题,但是这么写后,确实解决了问题,
        drawLTchart()     // 续上:页面加载完成后,dom不一定渲染完成了,所以这里的定时器是为了让dom渲染后再绘图
        drawRTchart()
        drawMiddleChart()
        drawBLchart()
        drawBRchart()
      }, 200)
    })
    

This solves the above two problems

But there is another question that I need to talk about. Obviously, I use elementplus as the UI framework. I particularly like the el-card component, so I often use it for layout, but I am using At that time, I found it difficult to master its layout rules, especially when combined with echarts to draw pictures, various DOM-related problems emerged one after another, so I had to give up using el-card, and secondly, I used div to do the layout myself. In fact, it’s just a matter of box shadow. Can’t you design? Of course, you don’t have to make your own wheels, just put various fancy border shadows~

Finished, hope all bugs are gone~

Guess you like

Origin blog.csdn.net/u012848304/article/details/132104000