前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【问题解决】解决 ECharts 图表窗口自适应与数据不渲染问题

【问题解决】解决 ECharts 图表窗口自适应与数据不渲染问题

原创
作者头像
sidiot
修改2024-04-16 22:09:50
2360
修改2024-04-16 22:09:50
举报
文章被收录于专栏:技术大杂烩技术大杂烩

前言

在项目中使用 ECharts 遇到了一些问题,包括图表不会随着窗口大小变化而变化,以及父组件向子组件传值时,ECharts 中的值不会被同步渲染等,因此写本博文进行记录;

博文中的所有代码全部收集在博主的 GitHub 仓库中,相关技术栈专栏如下:

快速上手 ECharts

在分析解决问题前,我们先复现一下情景。根据 ECharts 的官方文档,我们快速的在 Vue 中构建 ECharts 图表。

首先,根据官方文档的提示,在下载好的 ECharts 压缩包中提取 dist/echarts.js 放置在自己项目的目录下,并在项目中进行引用,代码如下所示:

代码语言:javascript
复制
<head>
    <meta charset="UTF-8">
    <title>ECharts 入门示例</title>
    <script src="../../vue.js"></script>
    <script src="../../echarts.js"></script>
</head>

接着,为 ECharts 准备一个 DOM 容器,代码如下所示:

代码语言:javascript
复制
<div id="main" style="width: 100%; height:400px;"></div>

最后,通过 echarts.init 方法初始化一个 ECharts 实例并通过 setOption 方法生成一个简单的柱状图,代码如下所示:

代码语言:javascript
复制
<script>
    const app = new Vue({
        el: '#app',
        data: {
            option: {
                title: {
                    text: 'ECharts 入门示例'
                },
                tooltip: {},
                legend: {
                    data: ['销量']
                },
                xAxis: {
                    data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
                },
                yAxis: {},
                series: [
                    {
                        name: '销量',
                        type: 'bar',
                        data: [5, 20, 36, 10, 10, 20]
                    }
                ]
            }
        },
        mounted() {
            this.initChart()
        },
        methods: {
            initChart() {
                let myChart = echarts.init(document.getElementById('main'));
                myChart.setOption(this.option);
            }
        }
    })
</script>

运行结果:

【ECharts 入门示例】代码点击此处跳转

图表自适应

在上述构建的场景中,图表并不会随着窗口大小的变化而变化,如下所示:

为了实现图表的窗口自适应功能,我们需要监听窗口的大小变化,并且同时调整图表的大小,代码如下所示:

代码语言:javascript
复制
mounted() {
    this.initChart()
    if (this.autoResize) {
        window.addEventListener('resize', this.resizeChart)
    }
},
methods: {
    ...
    resizeChart() {
        console.log('chart resize!')
        this.chart.resize()
    }
}

在上述代码中,autoResize 表示是否启动自适应功能,window.addEventListener('resize', this.resizeChart) 监听窗口的大小变化,如果窗口大小发生改变,则调用 resizeChart() 方法,resizeChart() 方法中使用了 ECharts 自带的调整图表大小的方法 resize()

运行结果:

不过眼尖的读者已经发现了,只是缩小了一点窗口的大小,该方法就被调用了85次,这对我们来说是没有必要的,因为我们不需要实时的去调整窗口大小,只需要在一定时间内完成调整即可,因此引入 loadsh 的防抖功能,代码如下所示:

代码语言:javascript
复制
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
代码语言:javascript
复制
methods: {
    ...
    resizeChart: _.debounce(function () {
        console.log('chart resize!')
        this.chart.resize()
    }, 100)
}

运行结果:

除了使用 loadsh 的防抖功能来节约资源,提高性能之外,还可以在 Vue 实例被销毁之前,取消监控并销毁 ECharts 实例,代码如下所示:

代码语言:javascript
复制
beforeDestroy() {
    if (!this.chart) {
        return
    }
    if (this.autoResize) {
        window.removeEventListener('resize', this.resizeChart)
    }
    this.chart.dispose()
    this.chart = null
}

【ECharts 图表自适应】代码点击此处跳转

数据不渲染

在前面的内容中,我们成功地开发了一个适用于特定场景的 Echarts 图表组件。为了让这个组件更具普适性和扩展性,我们计划对其进行一些改进和优化。

首先,我们将 div 元素的属性改进成动态绑定的方式,代码如下:

代码语言:javascript
复制
<div :class="className" :style="{ height: height, width: width }"></div>

然后,设置组件的 props 配置,这些 props 允许在父组件中给子组件传递数据,同时也为这些属性提供了默认值以防止属性未被传递时出现错误,代码如下:

代码语言:javascript
复制
props: {
  className: {
    type: String,
    default: "DataChild",
  },
  width: {
    type: String,
    default: "100%",
  },
  height: {
    type: String,
    default: "500px",
  },
  autoResize: {
    type: Boolean,
    default: true,
  },
  series: {
    type: Array,
    default: null,
  },
},

在上述代码中,父组件传入不同的 series 数值,可以动态的改变 ECharts 图表。

接着,我们开始构建父组件,代码如下:

代码语言:javascript
复制
<template>
  <data-child :series="this.series"></data-child>
</template>

<script>
import DataChild from "./DataChild.vue";

export default {
  name: "DataParent",
  components: {
    DataChild,
  },
  data() {
    return {
      series: [
        {
          name: "..",
          type: "..",
          data: [],
        },
      ],
    };
  },
  created() {
    this.fetchData();
  },
  methods: {
    fetchData() {
      ...
    },
  },
};
</script>

在上述代码中,通过 fetchData() 方法来获取需要渲染数据,这里的话使用 POSTMAN 来模拟后端服务器发送数据。

创建一个模拟服务器,设置 API 接口与响应数据:

对模拟服务器进行相关配置:

通过访问 API 接口来获取数据:

同时也能查看到请求日志:

在 Vue 中,我们通过 axios 来请求接口,代码如下所示:

代码语言:javascript
复制
fetchData() {
  const url = "";
  axios
    .get(url + "/test/data")
    .then((resp) => {
      this.series[0].data = resp.data.data;
      console.log(this.series);
    })
    .catch((err) => {
      console.log(err);
    });
},

然而出现了点问题,数据是请求到了,但是 ECharts 图表并没有渲染上:

我们在子组件中也打印一下相关数据,确认父组件的数据是否传递到子组件中,代码如下所示:

代码语言:javascript
复制
console.log('Child Data Before:', this.series)
this.initChart();
console.log('Child Data After:', this.series)

initChart() {
  ...
  console.log('Child Data:', this.series)
  this.chart.setOption(this.option);
},

子组件也确实获取到了数据,那为什么图表不渲染数据呢?

这是因为,当父组件需要通过异步 AJAX 请求获取数据来设置子组件的 props 属性时,可能会遇到子组件渲染速度快于 AJAX 请求返回的情况。这种情况下,父组件在 createdmounted 生命周期钩子函数执行时,子组件可能已经开始渲染,但是尚未接收到通过 AJAX 请求获得的数据,因此只有默认的 props 值会被子组件使用。

可以通过在父子组件中打点来得知程序的运行情况:

代码语言:javascript
复制
// parent
created() {
  console.log("Parent Created Before");
  this.fetchData();
  console.log("Parent Created After");
},
fetchData() {
  axios
    ...
    .then((resp) => {
      ...
      console.log("Parent Fetch Data");
    })
    ...
},

// child
created() {
  console.log("Child Created");
},
mounted() {
  console.log("Child Mounted Before");
  this.initChart();
  console.log("Child Mounted After");
  ...
},
initChart() {
  ...
  console.log('Child Init Data')
  ...
},

运行结果:

通过上述的运行结果可知,正如我们所预料的那样,由于父组件的 fetchData() 方法使用了异步请求,因此程序会一直执行下去,并不会因为没有获取到数据而阻塞,当子组件完成图表渲染 initChart() 后,父组件才请求到数据,**因此才造成了子组件图表中的数据不渲染问题**,子组件图表渲染时使用的数据是 props 中的默认值,即空数组。

那如何解决这个问题呢?其实很简单,我们只要监听对应的属性即可。

代码语言:javascript
复制
watch: {
  option: {
    handler(newVal, oldVal) {
      if (this.chart) {
        if (newVal) {
          this.chart.setOption(newVal);
        } else {
          this.chart.setOption(oldVal);
        }
      } else {
        this.initChart();
      }
    },
    deep: true,
  },
},

上述代码之所以监听的是 option 而不是 series,是因为在初始化图表时已经进行了赋值 this.option.series = this.series;series 本身是 option 的属性,通过 deep: true 也可以监听到 series 发生变化,同时监听 option 还能监听到其他属性。

运行结果:

【ECharts 数据不渲染】代码点击此处跳转

后记

以上就是 解决 ECharts 图表窗口自适应与数据不渲染问题 的所有内容了,希望本篇博文对大家有所帮助!欢迎大家持续关注我的博客,一起分享学习和成长的乐趣!✨

代码:

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 快速上手 ECharts
  • 图表自适应
  • 数据不渲染
  • 后记
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档