查看: 875|回复: 3

Vue集成Highcharts饼图组件封装与动态数据渲染

[复制链接]
发表于 昨天 10:00 | 显示全部楼层 |阅读模式
在Vue项目中使用Highcharts绘制饼图,常见做法是把图表容器封装成公共组件,再通过配置对象控制标题、提示框、图例、扇区点击和数据。原文示例适用于需要多个饼图、数据异步加载后再创建图表的页面。Highcharts与ECharts的差异原文也提到:ECharts免费,Highcharts商业用途需授权,个人使用会在图表上显示logo,选型时需结合授权场景。

一、安装与目录组织
先安装依赖:npm install highcharts。在components/commons下新建chart.vue作为图表基础组件;创建chart-options/options.js集中存放配置模型;业务页面引入chart组件和options。这样容器与配置分离,多个饼图可复用。

二、封装chart.vue
组件接收id和option两个props,id对应Highcharts渲染容器的DOM id,option是Highcharts配置对象。模板中保留一个带id的div。mounted中原文给出静态数据创建方式HighCharts.chart(this.id,this.option)的注释;动态数据场景下通过methods中的me()在数据准备好后执行创建。整理后的关键代码:
  1. <template>
  2.   <div class='x-bar'>
  3.     <div :id='id' :option='option'></div>
  4.   </div>
  5. </template>
  6. <script>
  7. import HighCharts from 'highcharts'
  8. export default {
  9.   props: {
  10.     id: { type: String },
  11.     option: { type: Object }
  12.   },
  13.   mounted() {
  14.     // 静态数据:HighCharts.chart(this.id, this.option)
  15.   },
  16.   methods: {
  17.     me() {
  18.       HighCharts.chart(this.id, this.option)
  19.     }
  20.   }
  21. }
  22. </script>
复制代码
这里需要注意:Highcharts.chart第一个参数是DOM id,模板中div的id必须与传入的id一致;动态数据不要在option尚未合并前调用me(),否则会拿到空series或空data。

三、配置options.js
options.js用构造函数维护pie配置,包含chart.type='pie'、title.text、tooltip.headerFormat/pointFormat、plotOptions.pie的allowPointSelect、cursor、dataLabels、showInLegend和events.click,以及series数组。series中colorByPoint为true,data初始为空,后续动态接收数据。funcc(op)通过Object.assign把传入的op.pie合并到this.pie。原文中let $back = $('#myBack')未被实际使用;如果项目没有引入jQuery,这行会带来额外依赖或报错,整理时可删除或确认已引入。关键配置如下:
  1. let Options = function() {
  2.   this.pie = {
  3.     chart: {
  4.       type: 'pie',
  5.       plotBackgroundColor: null,
  6.       plotBorderWidth: null,
  7.       plotShadow: false
  8.     },
  9.     title: { text: '' },
  10.     tooltip: {
  11.       headerFormat: '{series.name}<br>',
  12.       pointFormat: '{point.name}: <b>{point.percentage:.1f}%</b>'
  13.     },
  14.     plotOptions: {
  15.       pie: {
  16.         allowPointSelect: true,
  17.         cursor: 'pointer',
  18.         dataLabels: { enabled: true },
  19.         showInLegend: true,
  20.         events: {
  21.           click: function(e) {
  22.             // alert(e.point.url);
  23.             // window.open(e.point.url);
  24.             // location.href = e.point.url;
  25.           }
  26.         }
  27.       }
  28.     },
  29.     series: [{
  30.       name: '',
  31.       colorByPoint: true,
  32.       data: []
  33.     }]
  34.   }
  35. }
  36. Options.prototype.funcc = function(op) {
  37.   if (op.pie != null) {
  38.     this.pie = Object.assign(this.pie, op.pie)
  39.   }
  40. }
  41. export default new Options()
复制代码
tooltip的pointFormat使用point.percentage并保留一位小数;数据点若需要点击跳转,可按事件注释中的e.point.url、window.open或location.href实现,但原文只是预留注释,没有启用跳转。

四、业务页面引用与动态渲染
页面中放两个容器pie1、pie2,分别用x-chart渲染,传入id1/id2和option1/option2。data中option1、option2初始为null,等chartPie1等异步方法合并配置后再赋值。chartPie1返回Promise,内部调用options.funcc合并title和series;series.data支持数组简写和对象写法:['A', p1]、['B', p2]、['C', p3],D点用{name:'D', y:p4, url:'', sliced:true, selected:true}强调扇区,E点为['E', p5],p1到p5表示百分占比。合并后把options.pie赋给this.option1,resolve后在then中调用this.$refs.XChart1.me()创建图表。关键代码:
  1. <template>
  2.   <div class='pie'>
  3.     <div id='pie1'>
  4.       <x-chart ref='XChart1' :id='id1' :option='option1'></x-chart>
  5.     </div>
  6.     <div id='pie2'>
  7.       <x-chart ref='XChart2' :id='id2' :option='option2'></x-chart>
  8.     </div>
  9.   </div>
  10. </template>
  11. <script>
  12. import XChart from 'components/chart.vue'
  13. import options from './chart-options/options'
  14. export default {
  15.   data() {
  16.     return {
  17.       id1: 'pie1',
  18.       option1: null,
  19.       id2: 'pie2',
  20.       option2: null
  21.     }
  22.   },
  23.   components: { XChart },
  24.   methods: {
  25.     chartPie1() {
  26.       return new Promise((resolve, reject) => {
  27.         options.funcc({
  28.           pie: {
  29.             title: { text: '饼图1name' },
  30.             series: [{
  31.               name: '情况占比',
  32.               data: [
  33.                 ['A', p1],
  34.                 ['B', p2],
  35.                 ['C', p3],
  36.                 { name: 'D', y: p4, url: '', sliced: true, selected: true },
  37.                 ['E', p5]
  38.               ]
  39.             }]
  40.           }
  41.         })
  42.         let option1 = options.pie
  43.         this.option1 = option1
  44.         resolve()
  45.       }).then(resp => {
  46.         this.$refs.XChart1.me()
  47.       })
  48.     }
  49.   }
  50. }
  51. </script>
复制代码
原文data里还出现let option = options.bar,但后续实际使用的是options.pie,该变量未参与渲染,可视为遗留代码;整理时不必保留。另原文components: {XChart}后使用了中文逗号,复制到项目时必须改为英文逗号,否则编译会报语法错误。id重复也会导致Highcharts找不到容器或渲染到错误节点,页面中pie1/pie2与id1/id2需保持唯一对应。

五、排查与适用场景
如果图表不显示,优先检查:依赖是否安装、chart.vue的div id是否与传入id一致、me()是否在option赋值后调用、series.data是否已传入、funcc合并时是否覆盖了series、页面是否存在重复id、components对象是否使用英文逗号。该方案适合Vue2页面中多个Highcharts饼图复用同一配置模型、异步请求数据后渲染的场景;如果只是静态图表,可在mounted中直接创建;如果需要点击扇区跳转,可启用events.click中的e.point.url逻辑。选型上需注意Highcharts商业授权和个人使用logo显示的限制。
回复

使用道具 举报

发表于 昨天 19:00 | 显示全部楼层

Re: Vue集成Highcharts饼图组件封装与动态数据渲染

这个封装思路挺实用的,把图表容器和配置模型拆开,多个饼图复用会方便很多。动态数据场景下先合并 option 再调用 me 创建图表这个点很关键,不然容易拿到空 series。实际用的时候建议再注意几处:一是 options.js 导出的是单例,funcc 里 Object.assign 是浅合并,多个页面或多个图表连续合并可能互相污染,最好每次基于初始配置深拷贝或改成工厂函数返回新配置;二是 chart 组件里创建实例后保存起来,beforeDestroy 时调用 destroy,并在 option 变化时用 chart.update 或 setData,避免重复创建和内存泄漏;三是多个容器 id 要唯一,异步赋值后最好在 nextTick 里再创建图表,确保 DOM 已就绪;四是原文提到的 jQuery 那行没用就删掉,减少不必要依赖。事件点击跳转可以在 e.point.url 有值时才执行。整体选型部分提到 Highcharts 商业授权和个人使用 logo 也很值得留意。感谢分享。
回复 支持 反对

使用道具 举报

发表于 昨天 19:30 | 显示全部楼层

Re: Vue集成Highcharts饼图组件封装与动态数据渲染

看完这篇整理,整体思路很清楚:把图表容器和配置模型拆开,业务页面只负责异步取数再合并配置,多饼图复用确实省事。动态数据那块提醒得很到位,option 没合并完就调 me() 拿到空 series 是最常见的坑,用 Promise 的 then 里再通过 $refs 触发创建,顺序上比较稳。 补两个小点供参考。一是 funcc 里用 Object.assign 直接合并 this.pie,改的是同一个对象,如果页面上多个饼图共用这份导出的实例配置,后一次合并可能把前一次的 title、series 覆盖掉,建议每次返回前做一次深拷贝,或者把配置构造函数改成每次 new 一个,避免互相污染。二是组件销毁时最好把 Highcharts.chart 的返回值存下来,在 beforeDestroy 里调一下 destroy,不然切路由或反复创建容易残留实例和事件监听。 另外帖子里提到的 let $back = $('#myBack') 那行,既然没用到,删掉确实干净,省得项目没引 jQuery 时平白报错。click 事件里 e.point.url 的跳转注释按业务需要打开就行,D 点那种对象写法配合 sliced、selected 做重点扇区展示也很实用。 Highcharts 商业授权和个人使用显示 logo 的提醒也很有必要,选型阶段先确认清楚授权场景能少踩坑。感谢分享,收藏了。
回复 支持 反对

使用道具 举报

发表于 昨天 19:30 | 显示全部楼层

Re: Vue集成Highcharts饼图组件封装与动态数据渲染

封装思路整理得挺清楚的,容器与配置分离、动态数据合并后再调用 me() 创建图表,这两点对多饼图页面确实很实用。补充几个容易踩的点供参考。 第一,options.pie 通过 Object.assign 合并后又被赋给 option1、option2,如果两个图表共用同一个 options 实例,后一次合并会改到前一次的对象引用,图表之间可能互相串数据。建议在 funcc 里返回深拷贝,或者在业务页面赋给 option 时用 JSON.parse(JSON.stringify(...)) 或 lodash 的 cloneDeep 隔离一下,确保每个图表拿到的配置互不影响。 第二,模板里的 div 只留 id 就够了,ption 这个属性 Highcharts 不会读取,去掉更干净。另外 id 最好保证全局唯一,两个容器分别传 id1、id2 没问题,但如果组件复用多、层级深,可以考虑用 this.$el.querySelector 或 ref 加随机后缀,避免 DOM id 冲突导致 Highcharts 渲染到错误容器。 第三,异步赋值 option 之后马上调 me(),要确认 DOM 已经渲染完成,稳妥做法是 this.$nextTick 里再执行 me(),否则容器可能还没挂上。后续如果数据刷新,不建议反复 Highcharts.chart 重建,直接拿到实例用 cha
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-25 02:11 , Processed in 0.035496 second(s), 29 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部