前言:大屏数据可视化开发,有一个模块需要在swiper中使用echarts的饼图,由于是第一次使用这种搭配,所以记录一下踩坑
swiper设置的property不生效
swiper的实例化要放在dom挂载完成之后,首次初始化可以放在生命周期钩子mounted中,如果是放在异步请求中的话请使用nextTick包裹
echarts在slide中不显示
该问题可能由两个原因造成:
-
echarts实例化的时候是通过id绑定的
swiper在开启loop模式后会在复制第一个slide放到队列的最后,复制最后一个slide放到队列的最前面,形成无缝轮播,如果slide上面有id的话,页面中就会存在两个id相同的dom元素,所以这里建议使用class去绑定dom
-
echarts实例化的的时机
在swiper的实例化属性init中使用nextTick包裹echarts初始化即可
There is a chart instance already initialized on the dom.
出现这种问题的原因是我们的页面中使用了websocket,后台推送数据后导致数据改变,重新走了echarts的实例化,echarts的源码中对传入的dom对象进行了校验,如果传入的echarts对象的话则不会重新再走实例化的流程且抛出一个warn
我们可以拿到这个dom后使用echarts提供的getInstanceByDom方法判断这个dom是不是一个echarts dom,决定是否init
swiper loop模式下,echarts会丢失第一个slide的复制体的数据
swiper的loop模式开启的时候,后台推动送数据导致echarts重新实例化,然后就会出现第一页echarts不显示的bug,在这里我使用了一个临时解决方案,在收到后台推动的数据后调用swiper.destroy()销毁swiper,再重新实例化swiper,再在实例化echarts的时候判断是不是echarts dom,如果是的话,调用dispose()销毁这个echarts实例,再重新实例化echarts
上面这种操作有个问题,就是每次后台推送数据后,swiper会从跳到第一页重新loop,但是我还没想到更好的解决方案,所以就先这样吧(手动捂脸)
下面是一个demo,可以直接拿到vue项目中引用测试,里面使用了setInterval模拟了websocket推送数据
<template>
<div id="swiper" class="swiper-container">
<div id="wrapper" class="swiper-wrapper">
<div class="swiper-slide" v-for="item in arr" :key="item.id">
<div :class="`class${item.id}`" style="width: 600px;height:400px;"></div>
</div>
</div>
</div>
</template>
<script>
import Swiper from 'swiper'
import 'swiper/css/swiper.min.css'
import * as echarts from 'echarts'
export default {
name: 'TestCharts',
data () {
return {
swiper: null,
arr: [],
id: 0
}
},
watch: {
arr: {
handler (val) {
if (val.length) {
this.$nextTick(() => {
this.initSwiper()
})
}
},
deep: true,
immediate: true
}
},
created () {
for (let index = 1; index <= 2; index++) {
this.id = index
this.arr.push({
id: index
})
}
},
mounted () {
const timerId = setInterval(() => {
if (this.id >= 6) clearInterval(timerId)
this.id++
this.arr = []
this.swiper.destroy(true, true)
for (let index = 1; index <= this.id; index++) {
this.arr.push({
id: index
})
}
}, 30000)
},
methods: {
initSwiper () {
const self = this
this.swiper = new Swiper('#swiper', {
autoplay: true,
loop: true,
on: {
init: function () {
self.$nextTick(() => {
for (let index = 1; index <= self.id; index++) {
self.initChart(index)
}
})
}
}
})
},
initChart (index) {
// 指定图表的配置项和数据
const option = {
title: {
text: 'ECharts 入门示例' + index
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20].map(item => item * index)
}
]
}
// 使用刚指定的配置项和数据显示图表。
const divs = document.getElementsByClassName(`class${index}`)
divs.forEach(div => {
const myChart = echarts.getInstanceByDom(div)
if (myChart) myChart.dispose()
echarts.init(div).setOption(option)
})
}
}
}
</script>
<style lang="less" scoped>
/deep/.swiper-slide {
width: 600;
height: 400px;
background: skyblue;
}
</style>