vue封装echarts并实现大小动态自适应变化---超有用哇

一.先看效果:
大家好呀,⭐⭐⭐⭐⭐,秉着分享快乐的原则,我又来啦~

echarts不就是去官网复制然后粘贴吗,为什么要封装?

1.减少代码量,每次只要传宽度,高度与option配置项便能快速生成图表。
2.原先的echarts并不能自适应屏幕大小变化。
3.原先的echarts并不能自适应父盒子大小变化。

原先自适应存在问题(重):

1.当屏幕改变,图表不会重新动态改变并渲染:在这里插入图片描述

2.当图表标签的父盒子大小改变时,图表不会重新动态改变并渲染:
在这里插入图片描述
3.当屏幕改变,图表不会重新动态改变并渲染 (解决后) :

 在这里插入图片描述

 

4. 当图表标签的父盒子大小改变时,图表不会重新动态改变并渲染 (解决后) :

在这里插入图片描述

二.详细实现:

1. 组件要传的值:

先分析需求,比如组件名字为my-echarts,一般传个width(宽)、height(高)、option(配置项)这三个就可以了,如: 

  <my-echarts
        :width="'80%'"
        :height="'20vw'"
        :option="option1"
  ></my-echarts>

2. 实现组件代码:

在一个vue脚手架工程里,可以在components目录下新建一个 MyEcharts.vue 文件,具体功能代码看注释

<template>
  <!-- 定义标签 -->
  <div
    :id="id"
    :style="{
      width: width,
      height: height,
    }"
  ></div>
</template>

<script>
import * as echarts from "echarts";
// 2.生成一个 id 值给标签,目的是为了当多次使用组件防止id重复
const uid = function () {
  return new Date().getTime();
};
export default {
  //1.获取传过来的值
  props: {
    width: {
      typeof: String,
    },
    height: {
      typeof: String,
    },
    option: {
      typeof: Object,
      default() {
        return null;
      },
    },
  },
  data() {
    return {
      //3.在这定义 id 与 myChart图表实例 , 方便管理
      id: null,
      myChart: null,
    };
  },
  created() {
    // 4.id赋值
    this.id = uid();
  },
  mounted() {
    //   5. 创建echarts图表实例
    this.myChart = echarts.init(document.getElementById(this.id));
    // 指定图表的配置项和数据
    var option = this.option;
    // 使用刚指定的配置项和数据显示图表。
    this.myChart.setOption(option);
  },
};
</script>

3. 基本使用:
此时便可以在其它地方使用my-echarts组件,比如我在 App.vue使用该组件:

导入:

import MyEcharts from "./components/MyEcharts.vue";

注册:

 components: {
    MyEcharts,
  },

定义option数据,(可以随便去echarts官网复制一个):

data() {
    return {
      //三角形柱状图
      option1: {
        tooltip: {
          trigger: "axis",
          formatter: `{b}<br/>
                {a}: {c} 千人`,
        },
        //图表的内边距
        grid: {
          left: "3%",
          top: "20%",
          right: "3%",
          bottom: "1%",
          show: true,
          borderColor: "rgb(47,32,71)",
          containLabel: true,
        },
        xAxis: {
          data: ["衬衫", "羊毛衫", "雪纺衫", "裤子"],
          type: "category",
          axisLabel: {
            show: true,
            color: "rgb(142,175,220)",
          },
          axisTick: {
            //不显示刻度线
            show: false,
          },
          axisLine: {
            show: true,
            lineStyle: {
              width: 1,
              color: "rgba(47,32,71)",
            },
          },
          // 区域分割线
          splitLine: {
            show: false,
            lineStyle: {
              color: "rgba(204, 204, 204,0.3)",
            },
          },
        },
        yAxis: {
          name: "单位:千人",
          nameTextStyle: {
            color: "rgb(142,175,220)",
          },
          // 区域分割线
          splitLine: {
            lineStyle: {
              color: "rgba(47,32,71)",
            },
          },
          axisTick: {
            show: false,
          },
          axisLabel: {
            show: true,
            color: "rgb(142,175,220)",
          },
          axisLine: {
            lineStyle: {
              show: true, //是否显示坐标轴轴线,
              color: "white", //y轴轴线的颜色
              width: 0.5, //x轴粗细
            },
          },
        },
        series: [
          {
            name: "销量",
            //三角形柱状图
            type: "pictorialBar",
            barCategoryGap: "30",
            symbol:
              "path://M0,10 L10,10 C5.5,10 5.5,5 5,0 C4.5,5 4.5,10 0,10 z",
            //渐变色
            itemStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: "#188df0" },
                { offset: 0.5, color: "#188df0" },
                { offset: 1, color: "#83bff6" },
              ]),
            },
            data: [5, 20, 36, 10],
          },
        ],
      },
    };
  },

定义标签:

      <my-echarts
        :width="'80%'"
        :height="'20vw'"
        :option="option1"
      ></my-echarts>

4. 当屏幕改变,图表重新动态改变并渲染(重点):
echarts自带一个resize()方法能重新渲染绘制图表,但是要手动调用它,那么我们用window.onresize事件方法,当屏幕大小改变就调用echarts的resize()方法。

在 MyEcharts.vue 组件文件里添加:

。。。略
 mounted() {
    // 当屏幕改变,图表重新动态改变并渲染
    var that = this;
    window.onresize = function () {
      that.myChart.resize();
    };
  },
  。。。略

此时便可以:
在这里插入图片描述

5. 当图表标签的父盒子大小改变时,图表重新渲染(重):

这个方法我们新建一个mixin.js文件写,随意地方建,到时导入路径写对就行,然后在MyEcharts.vue里通过混入mixin.js文件,能更方便复用,代码实现详细看注释:

// echarts 自适应父盒子变化大小
const myMixin = {
  methods: {
    resize() {
      // 当宽高变化时就会执行
      //执行某些操作 重新改变图表, 同时传参,设置动画效果
      this.myChart.resize({animation: {duration:1000}});
    },
  },
    //自定义指令,图表的宽度采用百分比,父盒子宽度变化,那图表盒子大小也变化了,但是图表不会重新绘制
  //原理:判断盒子本身宽度改变了,再调用echarts的resize方法重新绘制
  directives: {
    // 使用局部注册指令的方式
    resize: {
      // 指令的名称
      bind(el, binding) {
        // el为绑定的元素,binding为绑定给指令的对象
        let width = "",
          height = "";
        function isReize() {
          //这个方法可以获取元素的css样式对象
          const style = document.defaultView.getComputedStyle(el);
          //对比跟上次宽度是否改变,如果改变了
          if (width !== style.width || height !== style.height) {
            //调用resize方法
            binding.value(); // 关键
          }
          //记录当前宽高
          width = style.width;
          height = style.height;
        }
        //设置监听器,每隔一段时间对比看看
        el.__vueSetInterval__ = setInterval(isReize, 300);
      },
      //只调用一次,指令与元素解绑时调用
      unbind(el) {
        //清除定时器
        clearInterval(el.__vueSetInterval__);
      },
    },
  },
}

export {myMixin};

 

在MyEcharts.vue 混入:

先定义自定义指令:

 <div
    v-resize="resize"
    :id="id"
    :style="{
      width: width,
      height: height,
    }"
  ></div>

然后在混入mixin.js:

import { myMixin } from "../assets/mixins/mixin.js";

export default {
  mixins: [myMixin],
//.....略
}

此时便实现如下:

在这里插入图片描述

6. 题外话:

第五步,说到底,是监听dom元素变化,我用的是定时器每隔一段时间监听一次,其实并不好,浪费性能。而 ResizeObserver API 这个新特性就可以帮助我们监听一个DOM节点的变化。但是这是一个实验中的功能,有兴趣可以自行查阅看看。

 原文:vue封装echarts并实现大小动态自适应变化---超有用哇_vue echarts 自适应_北极光之夜。的博客-CSDN博客

 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值