[Vue五]:vue和echarts结合,echarts图表自适应问题_vue echarts-程序员宅基地

技术标签: echarts结合vue  html绘制图表  前端  vue.js  vue中echarts的自适应  

一、echarts了解

作为一个前端开发人员,对于echarts应该是十分熟悉的,在日常开发中,大多数关于数据的展示是通过图表实现的,而rcharts则是图表展示的首选js库。

二、实现思路

在本例中实现一个页面中按照4x3的布局排列12个echarts折线图,并且每个折线图是通过父组件传值给子组件通过for循环实现的。
在这里插入图片描述

二、Vue项目中echarts的实现

1.导入echarts并注册
在当前文件夹下输入命令:

npm i echarts -S

在main.js中导入模块并注册:

import echarts from 'echarts'
Vue.prototype.$echarts = echarts

2.在在components目录新建subcomponents目录存放子组件,并在其下新建SubEcharts.vue组件作为子组件实现echarts绘图和接受父组件的参数:

<template>
  <div :id="echartsId" class="echarts"></div>
</template>

<script>
export default {
  /**父组件传值 */
  props:{
    idCode: {
      type: Number,
      required: true
    }
  },

  /**数据 */
  data(){
    return{
      xAxisData: [1,2,3,4,5,6,7,8,9,10,11,12],
      dataTest:[5,9,3,7,8,12,45,25,11,6,9,20],
    }
  },

  /**计算属性 */
  computed:{
    echartsId(){
      return 'echarts' + this.idCode
    }
  },

  /**挂在函数 */
  mounted(){
    this.drowLine()
  },

  methods:{
    /**绘制折线图 */
    drowLine(){
      let echarts = this.$echarts.init(document.getElementById(this.echartsId));
      let echartsid = document.getElementById(this.echartsId)
      echarts.setOption({
        backgroundColor:'#000',
        title: {
          text: 'vue项目中echarts的使用',
          textStyle: {
            color:'#fff',
            fontSize:18,
            fontWeight:'bold',
          },
          subtext:'作者:微信-迟亦早(chiyizao),csdn-goodlovingz',
          subtextStyle: {
            color:'#ddd',
          },
        },
        legend:{
          bottom:'5%',
          textStyle: {
            color: '#fff',
            fontSize: 12,
          },
          data: ['测试数据'],
        },
        tooltip:{
          show:true,
          trigger: 'axis',
          axisPointer: {
            type:'cross',
            crossStyle:{
              color:'#ddd',
            },
          },
        }, 
        grid:{
          left:20,
          right:20,
          top:80,
          bottom:20,
          containLabel:true,
        },
        xAxis: {
          show:true,
          axisLabel:{
            interval:1,
            rotate:-20,
            margin: 30,
            textStyle:{
              color:'#ddd',
              align: 'center'
            },
          },
          axisTick:{
              alignWithLabel:true,
              lineStyle:{
                color:'#ddd',   
              },
          },
          data: this.xAxisData,
        },
        yAxis: [
          {
            type:'value',
            name:'(人/次)',
            nameTextStyle:{
                color:'#ddd',
            },
            axisLabel:{
            textStyle:{
                  color:'#ddd',
            },
            },
            axisTick:{
              alignWithLabel:true,
              lineStyle:{
                  color:'#ddd',
                  
              },
            },
            splitLine:{
                show:false,
            },
          },
        ],
        series: [
          {
            type: 'line',
            name:'测试',
            stack:'人数',
            data: this.dataTest,
            label: {
              normal: {
                show:true,
                position: 'insideTop',
                offset:[0,20],
                textStyle:{
                  color:'#000',
                },
              },
              emphasis: {
                textStyle:{
                  color:'#fff',
                }, 
              },
            },
          },
        ]
      });
  }
}
</script>
<style>
.echarts{
  width: 100%;
  height: 35vh;
  background-color: #fff;
  margin: 5
}
</style>

在子组件中要注意:子组件中的div映射到父组件中作为一个单独的div,所以要求div的id不能重复,否则所有的echarts图形会绘制在第一个绘图区重叠和覆盖。因此,在子组件中我们对div的id绑定计算属性<div :id="echartsId" class="echarts"></div>,并且将父组件中传进来的数据进行组合形成唯一的id防止重复

/**计算属性 */
  computed:{
    echartsId(){
      return 'echarts' + this.idCode
    }
  },

子组件中用于绘图的数据都写死了,所以在自己运用时可以通过axios获取数据并整理成绘图的格式传入xAxis:的data和series相应处即可。

3.在components目录下新建EchartsRoot.vue的echarts布局组件,也就是父组件,并在父组件中导入绘图子组件:

<template>
  <div class="echartsStyle">
    <el-row>
      <el-col span="6" v-for="i in 12" :key="i">
        <subEcharts 
          :idCode='i'>
        </subEcharts>
      </el-col>
    </el-row>
  </div>
</template>
<script>
import subEcharts from '@/components/subcomponents/SubEcharts'
export default {
  components:{
    subEcharts
  }

}
</script>
<style>
.body{
  width: 100%;
  height: 100vh;
}
.echartsStyle{
  background-color:#000;
  width: 100%;
  height: 100px;
  margin: 10px
}
</style>

运用element-ui的layout布局使用v-for循环将绘图子组件subEcharts包裹起来实现4x3的页面布局,并且传入父组件的数据 i 供子组件的props的 idCode 接收:

	<el-col span="6" v-for="i in 12" :key="i">
        <subEcharts 
          :idCode='i'>
        </subEcharts>
    </el-col>

4.在Home.vue中添加跳转的按钮,跳转到echarts的展示组件EchartsRoot.vue
1)在路由router.js中实现home到echarts展示页面的路由的配置:

import Echarts from '@/components/EchartsRoot.vue'
		{
            path: '/echarts',
            component: Echarts
        }

2)在home的template中添加html元素,并在methods中实现跳转的方法:

<el-button type="primary" @click="toEcharts">echarts图表</el-button>
/**跳转到echarts界面 */
    toEcharts(){
      this.$router.push('/echarts')
    }

四、初步效果及问题

在这里插入图片描述
到这里已经基本实现了想要的效果,但是当拖动屏幕大小的时候,4x3的布局的每一个echarts图大小不会随着屏幕自动的改变大小对屏幕进行适应,极大的降低了用户的体验。

五、echarts图表对屏幕大小自适应

1、如果一个界面只有一个或者每个echarts图都是单独写方法绘制的,那么进行自适应很简单,只需要调用echarts对象的**resize()**函数即可:

//1.通过id获取html元素,调用echarts的init()方法进行初始化
let echarts = this.$echarts.init(document.getElementById('html元素id');
//2.在绘图的option完成后或者之前调用window.onresize函数并在其中实现echarts.resize()即可
window.onresize = function () {
  	echarts.resize()
}

2、对于上例通过v-for循环和父子组建结合,通过复用子组件的方式实现单页面多echarts图的方式这种方法明显行不通。因为在子组件中1方法只局限于当前循环,每个循环结束后子组件就会覆盖resize()方法,所以当图都加载完以后只有最后一个图能够自适应,其他图的resize()方法都在循环中一层一层的被覆盖了。
当然也可以按照其他思路实现所有图的自适应:在每一次for循环绘图结束时将此循环中的echarts对象传递到父组件一个数组或者列表中进行存放,当所有图都加载完以后在父组件中分别取出存放的每一个echarts对象调用resize()函数实现所有echarts图的自适应。(思路是这样的没问题,具体过程没有做!)
本例中采用另外的一种方法实现参考该博客:vue中使用echarts图表自适应的几种基本解决方案:在div上实现类似window的onresize 监听,这样既能实现图表的自适应,也不会因为页面跳转之后无法继续执行页面的onresize 方法!

1)在醒目的assets目录下新建esresize.js文件:

var EleResize = {
  _handleResize: function (e) {
    var ele = e.target || e.srcElement
    var trigger = ele.__resizeTrigger__
    if (trigger) {
      var handlers = trigger.__z_resizeListeners
      if (handlers) {
        var size = handlers.length
        for (var i = 0; i < size; i++) {
          var h = handlers[i]
          var handler = h.handler
          var context = h.context
          handler.apply(context, [e])
        }
      }
    }
  },
  _removeHandler: function (ele, handler, context) {
    var handlers = ele.__z_resizeListeners
    if (handlers) {
      var size = handlers.length
      for (var i = 0; i < size; i++) {
        var h = handlers[i]
        if (h.handler === handler && h.context === context) {
          handlers.splice(i, 1)
          return
        }
      }
    }
  },
  _createResizeTrigger: function (ele) {
    var obj = document.createElement('object')
    obj.setAttribute('style',
      'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden;opacity: 0; pointer-events: none; z-index: -1;')
    obj.onload = EleResize._handleObjectLoad
    obj.type = 'text/html'
    ele.appendChild(obj)
    obj.data = 'about:blank'
    return obj
  },
  _handleObjectLoad: function (evt) {
    this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__
    this.contentDocument.defaultView.addEventListener('resize', EleResize._handleResize)
  }
}
if (document.attachEvent) { // ie9-10
  EleResize.on = function (ele, handler, context) {
    var handlers = ele.__z_resizeListeners
    if (!handlers) {
      handlers = []
      ele.__z_resizeListeners = handlers
      ele.__resizeTrigger__ = ele
      ele.attachEvent('onresize', EleResize._handleResize)
    }
    handlers.push({
      handler: handler,
      context: context
    })
  }
  EleResize.off = function (ele, handler, context) {
    var handlers = ele.__z_resizeListeners
    if (handlers) {
      EleResize._removeHandler(ele, handler, context)
      if (handlers.length === 0) {
        ele.detachEvent('onresize', EleResize._handleResize)
        delete ele.__z_resizeListeners
      }
    }
  }
} else {
  EleResize.on = function (ele, handler, context) {
    var handlers = ele.__z_resizeListeners
    if (!handlers) {
      handlers = []
      ele.__z_resizeListeners = handlers

      if (getComputedStyle(ele, null).position === 'static') {
        ele.style.position = 'relative'
      }
      var obj = EleResize._createResizeTrigger(ele)
      ele.__resizeTrigger__ = obj
      obj.__resizeElement__ = ele
    }
    handlers.push({
      handler: handler,
      context: context
    })
  }
  EleResize.off = function (ele, handler, context) {
    var handlers = ele.__z_resizeListeners
    if (handlers) {
      EleResize._removeHandler(ele, handler, context)
      if (handlers.length === 0) {
        var trigger = ele.__resizeTrigger__
        if (trigger) {
          trigger.contentDocument.defaultView.removeEventListener('resize', EleResize._handleResize)
          ele.removeChild(trigger)
          delete ele.__resizeTrigger__
        }
        delete ele.__z_resizeListeners
      }
    }
  }
}
export {EleResize}

2)在SubEcharts.vue中导入esresize.js

import {EleResize} from '../../assets/esresize.js'

3)在SubEcharts.vue的绘图方法中,首先获取html的div元素,然后调用esresize.js的.on()方法

/**绘制折线图 */
    drowLine(){
      let echarts = this.$echarts.init(document.getElementById(this.echartsId));
      let echartsid = document.getElementById(this.echartsId)
      echarts.setOption({
        代码省略·····
      });
      
      let listener = function(){
        echarts.resize()
      }
      EleResize.on(echartsid,listener)
    },

至此,实现了多个方法不会覆盖的echarts图的自适应功能,效果图如下:
在这里插入图片描述

欢迎大家关注本人的微信公众号,微信公众号将不定期发送相应学习文章和教程

微信号:chiyizao

或者微信公众号搜索:
迟亦早

二维码

在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_31967985/article/details/100058547

智能推荐

Tomcat异常Serveral ports(8005,8080,8009) required by Tomcat v8.0 Server at localhost are already in_several ports (8005, 8080, 8009) required by tomca-程序员宅基地

文章浏览阅读2.2k次。在开始菜单->运行->cmd->输入netstat -ano命令,可以查看哪个进程占用了8080和8009端口,找到占用端口软件的PID,然后在任务管理器找到对应PID的软件,关闭结束该进程即可。可能是在打开Tomcat的情况下关闭了Eclipse/其他IDE,或是Eclipse/其他IDE非正常关闭,导致先前的Tomcat没有被关闭,端口占用。Connector 节点,将port="8080"中的端口改为一个没有被占用的端口,如10080。方法2:修改tomcat默认端口号。方法1:杀掉占用端口的软件。._several ports (8005, 8080, 8009) required by tomcat v8.0 server at localhost

饮料售卖机FSM_设计一个自动饮料售卖机画出fsm-程序员宅基地

文章浏览阅读452次。同步状态机状态机的类型mealymoore状态编码要求状态图代码仿真结果总结状态机的类型mealy输出与当前状态及输入有关本状态机应该就属于mealy状态机moore输出只与当前状态有关目前还没遇到这种状态机,我认为应该就是只有状态的转换吧,不考虑输入。状态编码我们知道有三种编吗方式;1.binary编码:状态描述简洁,占用较少寄存器资源,是比较常用的状态机编码方式;2.gr..._设计一个自动饮料售卖机画出fsm

291 蒙德里安的梦想(状态压缩dp)_291. 蒙德里安的梦想-程序员宅基地

文章浏览阅读246次。1. 问题描述:求把 N×M 的棋盘分割成若干个 1×2 的的长方形,有多少种方案。例如当 N=2,M=4 时,共有 5 种方案。当 N=2,M=3 时,共有 3 种方案。如下图所示:输入格式输入包含多组测试用例。每组测试用例占一行,包含两个整数 N 和 M。当输入用例 N=0,M=0 时,表示输入终止,且该用例无需处理。输出格式每个测试用例输出一个结果,每个结果占一行。数据范围1 ≤ N,M ≤ 11输入样例:1 21 31 42 22 32 42 11_291. 蒙德里安的梦想

MapReduce设计模式学习笔记_mapreduce四个阶段的任务-程序员宅基地

文章浏览阅读1.9k次。MapReduce_mapreduce四个阶段的任务

Linux 常见特殊符号-程序员宅基地

文章浏览阅读78次。[size=large][b]1,> 重定向输出符号 用法:命令 >文件名 特性:覆盖(当输入文件和输出文件是同一文件,文 件内容被清空;不适合连续重定向) 典型应用:合并文件(cat a b >c);清空文件(cat /dev/null);文件打印2,>> 重定向输出符号 用法:命令 >>文..._linux不同字体下的¥

DXF格式文件导入AD,做成可加工的PCB文件_ad怎么根据dxf文件绘制pcb-程序员宅基地

文章浏览阅读2.4k次。DXF文件导入AD注意事项也可以导入到KEEPOUT或者机械层对于有问题,可以tool菜单,reset,对于导入绿色是报错,相当于线宽不满足规则,没有改变线宽,默认为10mil=0.0127mm_ad怎么根据dxf文件绘制pcb

随便推点

C++中char转换short(或者int)要注意的现象_char数组转unsigned short-程序员宅基地

文章浏览阅读2.2k次。char temp = 0x80;cout << "unsigned short of 0x80=" << dec << (unsigned short)temp <<endl; //输出:unsigned short of 0x80=65408cout << "short of 0x80=" << dec << (short)temp <<endl; //输出:short of 0x80=-128un_char数组转unsigned short

AD学习笔记-程序员宅基地

文章浏览阅读106次。1、12345678设置为对齐快捷键(ctrl+左键可设置)2、尺寸要合适,不然在原理图中大小不一3、空格转向4、T+c可以快速加入新的元器件。

CSS3淡入淡出滑块-程序员宅基地

文章浏览阅读646次。CSS3 Fade slider Today I would like to show you how to create nice and smooth css3 slider. It uses fade effect to switch between slides. Plus, you can use custom promo text for each slide. We will use...

adb shell 命令行模拟发送开机广播android.intent.action.BOOT_COMPLETED测试开机自启动_am broadcast -a android.intent.action.boot_complet-程序员宅基地

文章浏览阅读1.2w次。开发中需求需要监听开机广播android.intent.action.BOOT_COMPLETED,然后让应用开机自启动。以前测试总是傻傻的关机然后再开机再验证有没自启动,很浪费时间,现在发现原来可以通过adb shell命令模拟开机广播,记录下模拟开机广播adb shell am broadcast -a android.intent.action.BOOT_COMPLETED当然..._am broadcast -a android.intent.action.boot_completed

windows环境Elasticsearch安装启动,配置ik分词器及安装head插件_es,ik,head启动-程序员宅基地

文章浏览阅读642次。整理一下windows版ES的简单部署过程1:安装ES官网下载ES的zip包,https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.4.2-windows-x86_64.zip下载好之后直接解压,然后在/bin下直接点击elasticsearch.bat启动这个就是成功跑起来了,接下来去浏览器访问,..._es,ik,head启动

蓝牙天线PCB设计-程序员宅基地

文章浏览阅读3.5k次。前言蓝牙(Bluetooth)是一种能够支持短距离无线通信的无线电技术,现已广泛应用于移动电话、便携式电脑等设备中,普遍接受它的工作频段为2. 4 GHz—2. 484 GHz。常见的蓝牙天线主要分为偶极天线、PIFA天线和陶瓷天线三种。PIFA天线属于单极子天线,它的反射损耗对地板大小比较敏感,同时,其远场辐射不均匀,难以满足手机、蓝牙耳机等终端设备对天线的全向辐射要求;陶瓷天线普遍增益较小;偶极天线易于实现较大的增益和较小的反射损耗,但其电长度一般都是波长的1/2。按此计算工作在2. 45 GHz的_蓝牙天线pcb设计

推荐文章

热门文章

相关标签