Vue 2.x折腾记 - 写一个挺不靠谱的Vue-Echarts组件

Posted crper

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue 2.x折腾记 - 写一个挺不靠谱的Vue-Echarts组件相关的知识,希望对你有一定的参考价值。

前言

上基友社区看了下,发现对echarts的封装都是打包进去的,想想就还是算了。

图表这货.说实在的,若不是整个系统大量用到,打包进去没必要。

CDN是个好东西,我们完全可以写一个异步加载JS然后封装按需调用。

至于你能学到什么,见仁见智了,若有所收获就是我这文章的意义所在了 。

效果图

实现思路及实现的功能

  • 异步引入echarts,有三个版本,不是最大也不是最小那个,具体上官网看
  • 图表的销毁释放内存
  • 图表跟随父包含块自适应(事件监听)
  • setOption的抽离,图表实例化id随机生成或者手动传入
  • setOption可以一次性传入整个图表的参数,也可以拆分传入(太多,只选了几个复用率很高选项的)…都设置了默认值.
  • 随机id是大写字母的组合,外部有传入则用外部的

代码

实现Vue.use(?)

index.js – 导出组件的,内部实在亮瞎眼


import echarts from "./echarts";

// Vue.use必须有install这个函数..可能我这里写的比较粗糙..有兴趣的可以去完善
// 用是可以正常使用的
export default 
  install: function(Vue, Option) 
    Vue.component("vue-echarts", echarts);
  
;

echarts.vue

<template>
  <div class="vue-echarts" :id="id" :style="style">
  </div>
</template>

<script>
  export default 
    name: 'vue-echarts',
    data: function () 
      return 
        loadJS: '', // 存储异步加载echart的promise状态
        chart: '', // 保存地图初始化的实例
      
    ,
    props: 
      id: 
        type: String,
        default: function ()  // 生成一个随机字符串,纯英文的,当不传入ID的时候生成实例,加i确保不会随机到一样的
          let temp = [];
          for (let i = 0; i < 6; i++) 
            let randomChar = String.fromCharCode(65 + Math.floor(Math.random() * 19) + i);
            temp.push(randomChar);

          
          return temp.reduce((pre, next) => pre + next);
        
      ,
      height:  // 图表高度
        type: String,
        default: '300px'
      ,
      width:  // 图表宽度
        type: String,
        default: '100%'
      ,
      legend:  // 以下的配置都是echarts官方图表的自定义部分,我拆分这么几大块
        type: Object,
        default: function () 
          return 
            data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
          
        
      ,
      title: 
        type: Object,
        default: function () 
          return 
            text: '堆叠区域图'
          
        
      ,
      tooltip: 
        type: [Array, Object],
        default: function () 
          return 
            trigger: 'axis',
            axisPointer: 
              type: 'cross',
              label: 
                backgroundColor: '#6a7985'
              ,
              animation: true
            
          
        
      ,
      toolbox: 
        type: Object,
        default: function () 
          return 
            show: true,
            feature: 
              dataZoom: 
                yAxisIndex: 'none'
              ,
              dataView:  readOnly: false ,
              magicType:  type: ['line', 'bar'] ,
              restore: ,
              saveAsImage: 
            
          
        
      ,
      grid: 
        type: Object,
        default: function () 
          return 
            left: '3%',
            right: '4%',
            bottom: '3%',
            containLabel: true
          
        
      ,
      xAxis: 
        type: [Array, Object],
        default: function () 
          return [
            
              type: 'category',
              boundaryGap: true,
              data: ['00:00', '02:00', '04:00', '06:00', '08:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '24:00']

            
          ]
        
      ,
      yAxis: 
        type: [Array, Object],
        default: function () 
          return [
            
              type: 'value'
            
          ]
        
      ,
      series: 
        type: [Array, Object],
        default: function () 
          return [
            
              name: '曝光',
              type: 'line',
              smooth: true,
              lineStyle: 
                normal: 
                  color: '#f00',
                
              ,
              data: [120, 132, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 120]
            ,
            
              name: '点击',
              type: 'line',
              smooth: true,
              lineStyle: 
                normal: 
                  color: '#20a0ff',
                
              ,
              data: [220, 182, 191, 234, 290, 330, 310, 120, 132, 101, 134, 90, 120]
            ,
            
              name: '点击率',
              type: 'line',
              lineStyle: 
                normal: 
                  color: '#42b983',
                
              ,
              smooth: true,
              data: [150, 232, 201, 154, 190, 330, 410, 120, 132, 101, 134, 90, 120]
            
          ]
        
      ,
      setOption: 
        type: Object
      ,
      dispose: Boolean

    ,
    computed: 
      style () 
        return 
          height: this.height,
          width: this.width
        
      
    ,
    created () 
      this.loadJS = this.loadEchartsJS();
    ,
    mounted () 
      this.loadJS.then(() => 
        let st = setTimeout(() => 
           this.init(); // CDNJS加载后,元素渲染后,初始化图表
        , 300);
      ).catch(err => 
        console.log('echarts js加载失败');
      );
    ,
    beforeDestroy () 
      window.removeEventListener('resize', this.chart.resize)
      if (this.chart) 
        this.chart.dispose(); // 销毁图表实例
      
    ,
    methods: 
      init ()  // 初始化图表
        this.chart = new echarts.init(document.getElementById(this.id));
        this.chart.setOption(this.setOption);
        window.addEventListener('resize', this.chart.resize) // 图表响应大小的关键,重绘
      ,
      loadEchartsJS ()  // 异步请求cdnjs
        const CDNURL = 'https://cdn.bootcss.com/echarts/3.7.1/echarts.min.js';
        return new Promise((resolve, reject) => 
          const script = document.createElement('script');
          script.type = "text/javascript";
          script.id = "cdnEchart";
          if (script.readyState)   //IE
            script.onreadystatechange = function () 
              if (script.readyState == "loaded" ||
                script.readyState == "complete") 
                script.onreadystatechange = null;
                resolve('success: ' + CDNURL);
              
            ;
           else   //Others
            script.onload = function () 
              resolve('success: ' + CDNURL);
            ;
          
          script.onerror = function () 
            reject(Error(CDNURL + 'load error!'));
          ;

          script.src = CDNURL;
          if (!document.getElementById('cdnEchart')) 
            document.head.appendChild(script);
          

        );
      
    ,
    watch: 
      setOption: 
        handler: function (newVal, oldVal)  // 监听外部传入的值,渲染新的的图表数据
          if (this.chart) 
            if (newVal) 
              this.chart.setOption(newVal);
             else 
              this.chart.setOption(oldVal);
            
            this.chart.resize();
           else 
            setTimeout(() => 
              this.init();
            , 300);
          
        ,
        deep: true
      
    
  
</script>




如何使用

  • main.js – 主入口文件,
// promise的polyfill
require("es6-promise").polyfill(); 
// 百度图表
import echarts from './components/common/echarts';
Vue.use(echarts);

总结

好吧,写这个东西花了一下午的时间,从构思到去查echarts api到实现;

粗糙的版本已经诞生,可能还有可以优化的地方,只能待我以后发现了再做调整了.

有更好的实现方案和思路的可以往下面留言。

以上是关于Vue 2.x折腾记 - 写一个挺不靠谱的Vue-Echarts组件的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2 + 折腾记 : 动手写一个不怎么靠谱的上传组件

vue-elementUi-Calendar前端日历插件折腾记

KB奇遇记:不靠谱的项目实施计划

vue-element-ui-Cascader 级联选择器支持多选---折腾记

Vue.js(2.x)之条件渲染

(汇总)Spring Boot 实践折腾记 & Spring Boot 2.x 实践记