解决vue3+echarts关于无法获取dom宽度和高度的问题

解决vue3+echarts关于无法获取dom宽度和高度的问题

近期写vue3项目,很多地方都用到了echarts,刚开始写的时候,发现图一直出不来,报错/报警内容一般有两项:

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

分别解释一下这俩报错

第一个报错是在初始化echarts的时候,没有找到对应的dom元素,所以需要在dom元素渲染完成后再初始化echarts图

第二个报错是说不能获取到echarts对应dom的宽或高,这个问题一般出现在设置dom节点的宽和高时,用了百分比形式,ECharts的宽高默认是以像素为单位的,并不能直接使用百分比来设置

经过多次尝试,总算解决这个问题了,记录一下解决方案

先上代码:

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

效果
在这里插入图片描述

代码我只放了图的那一部分,代码的作用是在页面的右侧画5张图,从我写的样式可以看出,所有画图的dom我都用了百分比,这样有个好处,不管什么屏幕,都可以比较好的显示,但是echarts并不支持百分比的宽高,所以狂报警

接下来解释一下代码:

  • import { driverAgeLT, driverAgeRT, driverAgeMiddle, driverAgeBL, driverAgeBR } from './graphOptions.js'这行代码是我把5张图的options都放到一个js文件里了,也是组件式开发的一个体现,这个文件我就不放上了,想怎么画图自己去设置

  • 下面这几行代码是关键,我直接通过注释的形式来解释

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

这样就解决了上面两个问题了

不过还有个问题得说一下,很明显,我用了elementplus作为UI框架,我特别喜欢el-card这个组件,所以很多时候我都用它来做布局,但是我在用的时候,发现我很难掌握它的布局规律,尤其是在结合echarts画图的时候,各种dom相关的问题层出不穷,所以我不得不放弃使用el-card,二是自己用div来做布局。其实也就是个盒子阴影的问题,不会设计?当然不用自己造轮子,放一下各种花式的边框阴影~

完,希望所有bug退散~

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
以下是一个在Vue中使用echarts的示例: ```vue <template> <div> <div id="myChart" :style="{width: '300px', height: '300px'}"></div> </div> </template> <script> import echarts from 'echarts' export default { name: 'Echarts', mounted() { this.drawLine(); }, methods: { drawLine() { let myChart = echarts.init(document.getElementById('myChart')); let option = { tooltip: {}, xAxis: { data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"] }, yAxis: {}, series: [{ name: '销量', type: 'bar', data: [5, 20, 36, 10, 10, 20] }] }; myChart.setOption(option); setTimeout(function() { window.onresize = function() { myChart.resize(); } }, 200) } } } </script> <style scoped> </style> ``` 在这个示例中,首先我们需要在`<script>`标签中引入echarts库,并在mounted钩子函数中调用`drawLine`方法。`drawLine`方法用于初始化echarts实例,并绘制图表。 在模板中,我们使用一个`<div>`标签来放置图表,并设置其宽度高度。通过`getElementById`方法获取到该`<div>`元素的DOM节点,并使用`echarts.init`方法初始化echarts实例。 然后,我们定义了一个`option`对象,用于配置图表的样式和数据。其中,`xAxis`代表横坐标,`yAxis`代表纵坐标,`series`代表数据系列。 最后,使用`setOption`方法将配置应用到echarts实例上,并通过`window.onresize`方法实现了图表的自适应。 这是一个简单的示例,你可以根据自己的需求进行更改和扩展。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [基于VUE + Echarts 实现可视化数据大屏公共服务大数据](https://blog.csdn.net/bigwhiteshark/article/details/126347181)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栀椩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值