自行封装的tabs组件配合echarts而出现的bug以及解决

简介: 自行封装的tabs组件配合echarts而出现的bug以及解决

前言⛹️‍♀️⛹️‍♀️


在上一篇文章中,我们成功的封装了tabs组件,这个组件我们实现了切换标题显示不同内容的功能,在一般状态正常使用下是没有什么问题,但是当我使用了echatrs的时候会出现问题


正常使用tabs情况下


image.png

可见这个是可以正常使用的,一般情况下没有问题,可以进行正常的渲染

代码片段:

image.png


引入echarts使用出错🤔🤔


问题一:未设置高度🥉🥉

但是当我引入echarts时,就出现了一些错误:这里只展示setup部分的代码

 setup() {
    // 这里需要获取tab-panel的DOM元素
    const ecart1 = ref<Ref>()
    const ecart2 = ref<Ref>()
    const ecart3 = ref<Ref>()
    onMounted(() => {
      const echart1 = echarts.init(ecart1.value as any)
      echart1.setOption({
        //...一些echarts的配置
      })
    })
    return {
      ecart1,
      ecart2,
      ecart3,
    }

此时在控制台报了这样的错误:

image.png

这个错误表明我们没有给盒子一个宽高导致的,那么我们可以给盒子一个宽高

image.png

问题二:未正确获取DOM🎃🎃


使用v-if遇到的问题

当时使用echarts的时候,我认为直接在onMounted中将echarts挂载到DOM元素中,这样应该就可以实现切换渲染图片,但是却会报错误:

image.png

这里面报错误是因为底层使用的是v-if来判断是否选中当前元素。而在初始化的时候,由于我们使用echarts注入了两个DOM结构,我们知道,v-if与v-show是不同的v-if是是否渲染的问题,而v-show是是否显示的问题,底层是修改display:none属性来实现的。

报出这样的错误其实可能是有一下几个原因:

  • 可能是将初始化放在vue的created阶段,因为这个时候dom还没挂载,所以获取不到,解决方法是把初始化放在mounted阶段来执行。
  • 还可能是 插入的元素的父元素或者祖先元素中有v-if(有条件渲染),而v-if绑定的条件绑定的变量是和后端返回的数据有关的,这样可能会出现dom未更新时图表就开始初始化,也会获取不到DOM。
  • Vue的DOM是异步更新的,只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部尝试对异步队列使用原生的 Promise.then 和MessageChannel,如果执行环境不支持,会采用 setTimeout(fn, 0)代替。

而我们在首次渲染的时候,只渲染了默认选中的那个页面,其他页面还没有渲染,因此另一个DOM还没渲染完毕,就会报出一个这样的错误 ,显然犯了上述的第二个原因。


如果我们改成v-show呢? 🛰🛰

会报出这个错误:

image.png

出现了下面的这个问题:

image.png

这个问题是为什么呢?

由于你使用了v-show,那么这个时候使用的是通过给每个元素修改display:none属性来控制显示和隐藏,那么当某个元素显示其他元素隐藏时,这个时候无法获取高度,因此会报出这个错误。因此这个虽然渲染出来了元素,但是依然无法实现相应的功能。

如何解决? 🚴‍♀🚴‍♀

因此现在我萌生了一个想法,就是能不能定义一个点击事件,在刚开始渲染的时候调用一次点击事件,然后在每次切换的时候调用组件渲染相应的echarts模块,这样,我们不就能解决问题了吗

 // 定义点击事件,接收子组件的数据
    const handelTabs = (data: any) => {
                init(data)
    }
    // 定义一个init函数,用于判断当前点击的标题元素
    const init = (value: string) => {
      if (value === 'first') {
        const echart1 = echarts.init(ecart1.value as any)
        echart1.setOption({
          //...配置echarts
        })
      } else if (value === 'second') {
        const echart2 = echarts.init(ecart2.value as any)
        echart2.setOption({
         //...配置echarts
        })
      }
    }
    onMounted(() => {
      // 默认第一次挂载的时候,调用函数
      handelTabs((tabs.value as any).default)
    })

这样就完成了我们上面所说的思想,但是这样还是会遇到问题,这是为什么呢?

image.png

首先我们来看这个handelTabs函数,这个函数被调用后会执行init函数,但是当切换的时候,因为我们使用的是v-if来判断,此时还没有渲染出来DOM元素,此时依然会报Uncaught Error: Initialize failed: invalid dom.这个错误,那么这又该如何解决呢?


nextTick的使用⚡️⚡️

首先解释一下为什么会出现这个情况:这里面就要设计到Vue数据更新的原理了(异步更新队列)

Vue在观察到数据变化时并不是直接更新DOM,而是开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。在缓冲时会去除重复数据,从而避免不必要的计算和DOM操作。然后再下一个事件循环tick中,Vue刷新队列并执行实际(已去重的)工作。所以如果用一个for循环来动态改变数据100次,其实它只会应用最后一次改变,如果没有这种机制,DOM就要重绘100次,过于耗费资源。

Vue会根据当前浏览器环境优先使用原生的Promise.then和MutationObserver,如果都不支持,就会采用setTimeout代替。

因此当你设置 改变了一个新数据data,DOM 并不会马上更新,而是在异步队列中,也就是下一个事件循环开始时执行更新时才会进行必要的DOM更新。如果此时你想要根据更新的 DOM 状态去做某些事情,就会出现问题。。

简单介绍一下nextTick:

定义:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

理解:nextTick(),是将回调函数延迟在下一次DOM更新数据后调用,简单的理解是:当数据更新了,在DOM中渲染后,自动执行该函数,

人话: 也就是说这样就可以在DOM更新完成之后就是执行回调,这样就可以更新完视图了

因此handelTabs函数要这样修改:

 // 定义点击事件,接收子组件的数据
    const handelTabs = (data: any) => {
      nextTick(() => {
        init(data)
      })
    }

这样就可以完成视图的更新,成功的渲染出来echarts了

image.png


总结 🥈🥈


解决了在使用tabs组件和echarts结合使用的时候会遇到的问题,并且还复习了nextTick的使用,我认为学习过程中可以及时的总结,找到问题的原因所在,然后解决它,这样是效率最高的学习方式

相关文章
|
6月前
若依框架 --- echarts 封装
若依框架 --- echarts 封装
333 0
ECharts 提示框组件Tooltip属性大全(包含文本注释)
ECharts 提示框组件Tooltip属性大全(包含文本注释)
388 0
|
26天前
|
资源调度 JavaScript API
vue-element-admin 综合开发五:引入 echarts,封装echarts 组件
这篇文章介绍了如何在vue-element-admin项目中引入并封装ECharts组件,以及如何实现折线图、柱状图和饼图的展示。
72 4
vue-element-admin 综合开发五:引入 echarts,封装echarts 组件
|
26天前
|
小程序 前端开发 JavaScript
微信小程序图表制作利器:ECharts组件的使用与技巧
微信小程序图表制作利器:ECharts组件的使用与技巧
48 1
这样封装echarts简单好用
这样封装echarts简单好用
ECharts 饼图切换数据源bug 开始没数据显示 切换或刷新后显示
ECharts 饼图切换数据源bug 开始没数据显示 切换或刷新后显示
145 0
|
6月前
|
前端开发 JavaScript
React中封装echarts图表组件以及自适应窗口变化
React中封装echarts图表组件以及自适应窗口变化
203 1
|
6月前
|
JavaScript
封装echarts china map geo实现dispatch触发geoSelect事件高亮显示某个省份和城市,并定义复杂样式
封装echarts china map geo实现dispatch触发geoSelect事件高亮显示某个省份和城市,并定义复杂样式
|
12月前
|
JSON 小程序 前端开发
小程序Echarts图表组件使用
小程序Echarts图表组件使用
77 0
ECharts分段型视觉映射组件的属性修改
ECharts分段型视觉映射组件的属性修改
59 0