背景
这三天,在Vue项目中,利用echarts的热图echarts 加载问题,实现了一个类似kibana机器学习的数据预测图。 不同之处在于我使用选项卡在概述和特定 IP 例外之间切换。
在实现过程中,我踩到了echarts的两个陷阱。 以下是该过程的摘要。
功能说明
当你访问kibana官方的任务视图时,你会看到这样一张异常的数据热图:
kibana异常数据查看
作者使用制表符来分隔概述和攻击信息:
作者实现的视图
序号②区域封装了一个Vue组件DataGraph.vue,在两个选项卡中都引用了该组件:
DataGraph.vue组件实现时,如果绘图区域共享一个div,会出现一个严重的问题,就是切换时另一个tab标记的图片是空白的。 我们一起来分析一下这个问题。
热图区域使用同一个div的问题
从组件概念来看,理论上,一个父组件两次引用同一个子组件,本质上是一个不同的组件。 绘图 div 共享一个,并且应该在各自的子组件区域中绘制。
概述和攻击IP的区别在于,前者没有搜索框,但两者都有热图,因此提取了共同的组件。 考虑到这一点,作者最初写道:
异常数据时间线
第一步,启动应用程序,进入“Overview”,可以看到热图:
概览视图
第二步,定位到tab,看到它的元素有一个id异常的div,并且第二个tab的Panel因为延迟加载还没有渲染出来:
概览元素视图
第三步,切换到第二页,结果却是空白:
攻击IP查看
第四步,定位TabPanel2的元素信息,看到它有一个与TabPanel1 id相同的div,但是内容为空:
攻击IP视图 元素视图
第五步切换回home,发现热力图发生了变化:
重新渲染概览视图
调试代码,发现切换到第二页时,创建的echart实例的id仍然是ec_1592993260650,与第一页是同一张图片,因此推断渲染仍然发生在第一页。
组件中多次引用 echart 会造成混乱
这令人惊讶:明明被引用了两次,但理论上它是两个子组件?
仔细查看了绘制方法后,我终于明白了问题的关键:
const allAnomalousOptionCharts = echarts.init(document.getElementById(chartId));allAnomalousOptionCharts.setOption(allAnomalousOption);
echarts绘制时,会使用document.getElementById,在整个文档中查找某个id的元素,然后完成渲染。 重复引用,整个文档中有两个id相同的元素,所以渲染到第一个div上。
解决方案
DataGraph.vue组件使用多个divecharts 加载问题,不同的标签页使用不同的div。 修改实现并添加一个div:
// 定义元素
无异常数据
// 绘制 let ChartId = 'anomalous1';if (!this.isAll) { ChartId = 'anomalous2';} const allAnomalousOptionCharts = echarts.init(document.getElementById(chartId)); allAnomalousOptionCharts.setOption(allAnomalousOption); v-show 和 v-if
另外,关于页面无数据时和有数据时的功效,作者用了一个“无数据”的文字,并尝试使用v-show来动态控制绘图组件的显示和隐藏:当有数据时,没有数据,绘图区域隐藏,显示“无数据”。 数据”文本。
测试发现这种方式不行,具体表现是:
当v-show控制echarts的div的显示和隐藏时,当js完成echarts的实例化时,虽然v-show的属性已经设置为true,但是此时页面没有div,最终导致绘图失败。
解决方案:使用v-if强制渲染div,并调用this.$nextTick将绘制逻辑作为反弹,保证图形能够正确绘制。