在vue下封装echarts公共组件的总结
这几天公司里边有一个项目,叫做日控制台,该项目是在webview下的一个webapp,使用vue构建,项目中要求使用许多自定义的图表。考察了许多图表组件之后,发现echarts是所有表库中,最灵活,特效最好看的一种。一、构建基础公共组件1. 实现基础功能
在echart官网上搜索到,如何使用# 1. 获取一个用于挂在 echarts 的 DOM 元素 let $echartsDOM = document.getElementById("echarts-dom") # 2. 初始化 let myEcharts = echarts.init($echartsDOM) # 3. 设置配置项 let option = {...} # 4. 为 echarts 指定配置 myEcharts.setOption(option)
使用echart的步骤也就这几部,就是先获取到承载echart实例的dom实例,然后调用init()方法初始化图标实例,最后调用setOption()方法传入配置项
这几步都要在vue的mounted方法下实现.mounted() { let $echartsDOM = document.getElementById("echarts-dom") let myEcharts = echarts.init($echartsDOM) let option = { title: { text: "ECharts 入门示例" }, tooltip: {}, legend: { data: ["销量"] }, xAxis: { data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"] }, yAxis: {}, series: [{ name: "销量", type: "bar", data: [5, 20, 36, 10, 10, 20] }] } myEcharts.setOption(option) } }
注:在 Vue 中,首先我们需要使用 import echarts from "echarts" 以引入 echarts。二、组件化
思路很简单,就是将业务上用到的图表,比如柱状图、折线图,通通封装成组件,然后再main app文件中调用,通过分析,可以通过传props,来改变setOption()方法中的对象,达到封装不同图表组件的目的。
将之前的options转移到main app中的data对象之中。
注:echarts图表要求承载的容器具有固定的宽高才能正常显示.echarts-container{ width: 100%; height: 20rem; }1. 组件优化-props的series校验
如果在传入组件的props中传入了空对象,就会发现,图表会抛出一个错误,即
Error: Option should contains series.
原因就是传入的 option 配置对象不含有 series 键,所以,默认值处理是需要存在的,即当调用方传入的对象为空或不存在 series 配置时,应在页面上显示一些提示( 对用户友好的提示,而不是对编程人员 ),即避免因报错而造成空白的情况。
此外,当我们像之前那样给 option 这一参数进行类型限制后,倘若调用方传入非对象类型,Vue 会直接抛出错误——这一结果也不是我们想要的。我们应该取消类型限制,并在 option 发生变化时进行依次以下判断:// 1. 是否为对象; export function isObject(option) { return Object.prototype.isPrototypeOf(option) } // 2. 是否为空对象; export function isEmptyObject(option) { return Object.keys(option).length === 0 } // 3. 是否包含 series 键; export function hasSeriesKey(option) { return !!option["series"] } // 4. series 是否为数组; export function isSeriesArray(option) { return Array.isArray(option["series"]) } // 5. series 数组是否为空。 export function isSeriesEmpty(option) { return option["series"].length === 0 } export function isValidOption(option) { return isObject(option) && !isEmptyObject(option) && hasSeriesKey(option) && isSeriesArray(option) && !isSeriesEmpty(option) }
然后在组件中引入最后的isValidOption方法作为判断,我们先使用一个watch监听options的变化 watch: { options(options){ this.checkAndSetOption() } }, methods: { checkAndSetOption(){ let options = this.options if(isValidOption(options)){ this.myEcharts.setOption(options) this.isOptionAbnormal = false }else{ this.isOptionAbnormal = true } } }
这里的checkAndSetOption方法是判断传入的option是否合法,如果合法,就执行setOption,isOptionAbnormal变量是监控页面是否显示options非法的flag。
同样的dom样式上的改变,也要使用v-show来判断isOptionAbnormal是否要渲染图表和渲染错误信息。 数据为空 .oc_echarts_container, .echarts { width: 100%; height: 100%; } .shadow { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; font-size: 1rem; color: #8590a6; }2. 增强组件功能 - 数据加载提示 数据加载中...
在组件内部需要一个外部的props,isLoading,但是这里需要注意,在 Vue 中,v-show 使用 display 控制组件的显隐。而当 echart init 的时候,如果其挂载 DOM 的 v-show 处于 false 状态,则其 init 的对象宽高都是 0。即使之后 v-show 状态改变,由于 mounted 生命周期不会再次触发,从而使得 echarts 显示不正常。所以需要使用css的visibility来控制显隐。computed: { isChartVisible() { return !this.isLoading && !this.isOptionAbnormal } }, 3. 组件复用-随机ID
echarts 进行 init 挂载时使用的是 DOM 元素的 ID。而在组件中,我们设置的 ID 是固定的( 注意与 scoped css 进行区分 )。如果多个组件的 ID 是相同的,只有一个组件会被 echarts 挂载。
所以我们要设定一个随机的randomId,赋值到承载echarts图表的dom元素的id中 三、延迟加载
延迟加载是组件的一个优化,在业务的开发中可以看到,一个页面往往有着许多的图表,图标伴随着许多异步请求和canvas渲染,如果一次性渲染所有的图表会导致许多的性能问题。这里想到的一个解决方案就是延迟加载。
用通俗的话讲就是,页面滚动到哪张图表就去渲染哪一张图表。
完成这一功能需要以下步骤:监听页面滚动事件;滚动事件中获取 echarts 的位置;在页面当前位置达到 echarts 位置的时候进行 echarts 的初始化。1. 监听页面滚动
如果要监听页面滚动,需要用到dom的监听器,addEventListener("scroll", [funciton])。这样就能为每一个组件附上监听事件。2. 获取当前滚动下边界和组件的上边界
这一个步骤需要封装成一个函数,checkPosition()checkPosition() { let windowHeight = document.documentElement.clientHeight||window.innerHeight let scrollTop = document.documentElement.scrollTop || document.body.scrollTop let windowBottom = scrollTop + windowHeight const selfTop = _.get(this.$refs, "selfEcharts.offsetTop", 0); if(windowBottom >= selfTop) { this.isPositionReady = true this.checkAndSetOption() window.removeEventListener("scroll", this.scrollEvent) } },windowBottom(滑动的下边界) = scrollTop(屏幕当前滑动的距离) + windowHeight(窗口的高度)selfTop(当前组件的顶部位置)
当第一个变量大于第二个变量时,就认为滑动到了该图表组件,就开开启加载3. 初始化data() { return { myEcharts: null, isOptionAbnormal: false, randomId: "echarts-dom" + Date.now() + Math.random(), scrollEvent: _.throttle(this.checkPosition, 500), // 滑动事件 isPositionReady: false, //控制数据异步与页面滚动先后顺序的flag } }, mounted() { let $echartsDOM = document.getElementById(this.randomId) if(!$echartsDOM) return this.myEcharts = echarts.init($echartsDOM) // 第一次未滑动的时候 this.checkPosition() //滑动之后的监听 window.addEventListener("scroll", this.scrollEvent) },
checkPosition方法不仅要在scroll监听事件中调用,在组件第一次渲染的时候也要调用一次进行初始化,不然,组件无法正常渲染图表。4.节流
组件代码经过测试之后发现,如果滚动过于快速,会不停的调用checkPosition(),关键是这个方法会不停的去setOption(),所以以上代码均采用了lodash的throttle节流方法,在500毫秒内只允许调用一次。5. 解绑监听事件
解绑事件,组件中有设定监听器,如果该图表已经被加载了,那么这个监听器就没有作用了。window.removeEventListener("scroll", this.scrollEvent)
这段代码就是解绑监听器,多多少少会优化一下速度吧。因为增加监听和解绑监听的时间函数要求一致,所以在data中新增了scrollEvent,顺便把节流函数一起加了上去。6. 请求异步控制setOption
由于用于渲染 echarts 的数据常常是异步获取的,也就是说,option 可能会在异步调用结束之后更新,从而触发 option 的 watch,进而导致 this.checkOption()执行,最终使得 setOption 在页面没有滚动到合适位置时就触发了。
为了解决这个问题,我们应该让 setOption 的过程受制于一个标识位,而该标识位会在页面滚动到合适位置时置为 true,从而杜绝由于 option 更新、触发 watch 而导致的漏洞。
首先,我们要添加一个新的 data,取名为为 isPositionReady,然后,在 checkAndSetOption() 中加入对该标识位的判断:最后,在位置检测方法 checkPosition() 中,当达到合适位置时,将该标识位置为 true checkPosition() { // .... if(windowBottom >= selfTop) { this.isPositionReady = true // .... } }, checkAndSetOption() { // .... if(!this.isPositionReady) return //.... }四、echarts重绘
这里的重绘指的是 ehcarts 中的 resize() 方法。用于在某些时刻进行 echarts 的调整,包括:组件宽度设置为百分比,浏览器宽度发生变化时;页面收缩元素状态改变,如侧边栏收缩导致内容区宽度变化;1.页面宽度改变
继续增加监听器就能完成window.addEventListener("resize", _.throttle(() => { this.myEcharts.resize() console.log("---") }, 500))
研究每天喝八杯水对大部分人而言是过量的每天喝2公升水是目前流行的建议饮水量。一天要喝八杯水经常出现在日常健康指南中,似乎也已成为大家公认的水分摄取标准。然而据科学研究,对大多数人来说,每天喝八杯水的建议饮水量其实是过量
每天张开嘴做这件事的人,健康不会太差!一定要坚持爱笑的人,运气不会太差!经常笑的人,身体也不会太差!当你咧嘴笑的时候,身体内部在发生什么?心脏更健康笑能增加心脏血流量,促进血液循环,减少心脏病的发作。另外,大笑还能起到扩张血管提
jack马去哪了不久前马斯克在接受节目采访时被提问一个问题你是怎么看待中国的科技和互联网企业家的现状?马斯克摸了摸下巴whereisjackma?这句话突然点醒了很多了,马云去哪了?阿里巴巴前CE
翌圣上市与诺唯赞头对头比较原文发表于微信公众号(20220624)翌圣和诺唯赞其业务相关性很大,因此对其进行头对头比较显得尤其必要。免责声明本人不持有二者股票股份或其他权益,亦不打算在未来6个月内买入受让二
刘晓春金融支持实体经济不是简单让利关键是通过制度设计,让金融机构发挥市场有效配置资源的作用。简单让利支持大批在市场上不堪一击的低效能企业,只会弱化中国经济的竞争力,最终有违支持实体经济高质量发展的初衷文刘晓春金融支
如何才能证明董路这个路线失败了?你得看足球小将的目标是什么?决赛输给鲁能,获得亚军。失败与否,你得看足球小将的目标是什么足球小将的目标是尽可能推迟家长让孩子AllIn足球或AllIn学习的决策时间点,避免赌博式青训,避免五年级觉得自己孩子拔
大家看世界杯了吗?来小说中感受一下足球的魅力吧2022年卡塔尔世界杯至今已开赛一段时间,不管是不是球迷,相信各位看官们近段时间来都刷到过不少关于世界杯的消息。接下来,我要推荐的就是几篇不错的足球的小说。各位对足球感兴趣的看官们
将帅不合!特雷杨和主教练麦克米兰发生冲突在老鹰主场击败掘金的比赛里,我们发现老鹰主将特雷杨并未出战比赛,原本大家认为是特雷杨因伤缺阵,结果却是特雷杨在先前的球队训练里拒绝主教练麦克米兰要求其参加投篮训练导致的。据悉当时特
SoC国产紫光展锐5G新U跑分曝光接近骁龙765G天玑900日前,国产芯片厂商紫光展锐发布了一颗新UT820,台积电6nmEUV工艺,1A76大核2。7GHz3A76大核2。3GHz4A552。1GHz,支持5G等,主要规格昨天给大家汇总了
延期的小米13!确定涨价每年,黑马最期待的发布会,除了苹果华为,就是小米了。躲过了苹果与华为之间的神仙打架,小米新品总喜欢在年底冲刺发布。不过,由于众所周知的原因,原定于12月1日举行的小米13系列新品发
韩国球员称讨厌日本队晋级16强引日媒不满韩国球员曹圭成海外网12月5日电据韩媒朝鲜日报12月5日报道,韩国足球运动员曹圭成日前称讨厌日本晋级16强,引发日本舆论不满。北京时间12月3日,卡塔尔世界杯小组赛,韩国队21战胜