开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情
前言
最近在使用 **echarts** 的时候碰到了这么一个报错,
造成报错的原因是因为 **echarts** 的图形容器还未生成就对其进行了初始化,
下面几种方法是经本人自测最有效的解决方案。
错误原因分析:
1、 初始化 echarts 的 DOM 元素不存在。
2、 使用echarts并且在容器上使用了v-if出现这种情况。
3、 html元素还没加载或者代码还没有执行完就先执行了echarts 的渲染,也就是代码执行前后顺序的问题。
解决方案:
第一种方法:
将 created(){} 生命周期中的方法放在 mounted(){} 生命周期中,该方法思路是因为数据渲染方法放到了 created(){} 生命周期中,但是数据还未取到,页面已经加载了,故放在 mounted(){} 生命周期中,在初始化页面完成后,再对 DOM 节点进行相关操作。
mounted() {
this.myEcharts();
},
第二种方法:
根据报错信息查找原因发现是因为 实例化echarts的元素不存在,查看官方文档代码示例:
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
基于准备好的dom,初始化echarts实例,也就是只有 页面存在的HTML元素 才可以去初始化。但是有时候会出现获取不到dom容器的情况,,说白了就是执行顺序的问题,
所以就将获取节点的方法document.getElementById()的方式更换使用vue的ref与$refs来进行获取图表容器节点就行
<div id="Echarts" ref="Echarts"></div>
mounted() {
this.myEcharts();
},
methods: {
myEcharts() {
//var Echarts = document.getElementById('Echarts');
var Echarts = this.$refs.Echarts;
// 将之前的方法更换为$refs来进行获取
// 在进行判断当前节点存在后进行echarts图表数据的填写
if (Echarts){
console.log('bar_dv不为空');
let myChart = this.$echarts.init(Echarts)
图表代码 ...
}
}
}
正常开发难免调用接口返回数据渲染,可能更改为ref与refs的方法不能完全解决这个问题。这个时候就可以在async await接口之后,这ref与$refs的方法的基础上添加一个定时器来延时执行
<div id="Echarts" ref="Echarts"></div>
mounted() {
// 进入页面请求数据
this.myData();
},
methods: {
async myData(){
let {code, data, msg } = await myData()
if(code == 200){
this.xxx = data
// 数据请求成功 --- 添加定时器setTimeout 将任务更改为异步
setTimeout(() => {
this.myEcharts();
},500)
}else{
return false
}
},
myEcharts() {
var Echarts = this.$refs.Echarts;
// 将之前的方法更换为$refs来进行获取
// 在进行判断当前节点存在后进行echarts图表数据的填写
if (Echarts){
console.log('bar_dv不为空');
let myChart = this.$echarts.init(Echarts)
图表代码 ...
}
}
}
第三种方法:
最后的情况就是添加this.$nextTick方法 我们需要 包裹在渲染图表的方法外层等待dom加载完成后执行的钩子
该方法思路是将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。
<div id="Echarts" ref="Echarts"></div>
mounted() {
// 进入页面请求数据
this.myData();
},
methods: {
async myData(){
let {code, data, msg } = await myData()
if(code == 200){
this.xxx = data
// 数据请求成功 --- 添加定时器setTimeout 将任务更改为异步
// 添加$nextTick dom加载完后执行的钩子
this.$nextTick(() => {
setTimeout(() => {
this.myEcharts();
},500)
})
}else{
return false
}
},
myEcharts() {
var Echarts = this.$refs.Echarts;
// 将之前的方法更换为$refs来进行获取
// 在进行判断当前节点存在后进行echarts图表数据的填写
if (Echarts){
console.log('bar_dv不为空');
let myChart = this.$echarts.init(Echarts)
图表代码 ...
}
}
}
第四种方法:
其实解决很简单,只需要将v-if更换成v-show即可。对比v-if和v-show的不同和渲染机制就可以。简单理解一点,深层的dom渲染机制不理解。大佬可以补充
<div id="Echarts" ref="Echarts" v-if="shipEcharts"></div>
<div id="Echarts" ref="Echarts" v-show="shipEcharts"></div>
总结
四种方法
- 放在 mounted(){} 生命周期中
- 使用vue的ref与$refs -- 实际开发async await中可添加一个定时器
- 添加this.$nextTick方法
- v-if更换成v-show