源代码
图表大小自适应-代码地址
需要效果如下(无节流版效果)
我们可以看到没有节流会有一点卡顿
思路
1、把这三个图表抽离出一个公共组件
2、在组件内进行监听窗口 window.addEventListener('resize', fn)
3、最后组件直接响应图表视图chart.resize()
笔者这里用的是vue
,所以以vue
为标准
1、创建公共组件chartComponent.vue
组件
props
接收chartId
, echarts绑定的对象domId
,
组件props
接收option
, echarts的options
属性,
图表渲染完成事件参考之前写的一篇
创建图表公用组件chartComponent.vue
javascript
<script>
import * as echarts from 'echarts'
export default {
name: 'chartComponent',
props: {
chartId: { type: String, required: true },//图表id
option: { type: Object, default: () => {} }, //图表属性
loading: { type: Boolean, default: false }// 可不写loading状态
},
data() {
return {
myChart: null,
isFinished: false
}
},
methods: {
drawChart() {
this.myChart.setOption(this.option, true)
},
chartResize() {
this.myChart.resize()
console.log('重置大小')
}
},
mounted() {
if (!this.myChart) {
this.myChart = echarts.init(this.$refs[this.chartId])
}
//监听窗口大小变化
window.addEventListener('resize', this.chartResize)
this.drawChart()
this.myChart.on('finished', () => {
if (!this.isFinished) {
console.log('finished')
this.isFinished = true
this.myChart.resize()
}
})
},
beforeDestroy() {
//销毁window监听对象
window.removeEventListener('resize', this.chartResize)
if (this.myChart) this.myChart.dispose()
this.myChart = null
},
watch: {
//数据可能是异步的,用watch接听接收
option: {
handler(newVal) {
const options = newVal
this.drawChart(options)
},
deep: true
}
}
}
</script>
复制代码
html,css
<template>
<div class="chart-box" :ref="chartId"></div>
</template>
<style lang="scss" scoped>
.chart-box {
width: 100% !important;
height: 100% !important;
}
</style>
复制代码
2、使用
- 直接引入使用就好
<chartComponent chartId="chart_a" :option="option"></chartComponent>
复制代码
细心的朋友发现没有节流,好了,我们在chartResize
上增加节流, 没有节流会有明显的卡顿
3、增加节流
1、引入节流方法(可以自己网上找,也可以用
lodash
的节流),这里就不写节流的具体内容
2、在chartResize
方法上绑定节流
- 在
chartCompont
中引入throttle
方法
import { throttle } from '../util/tool'
//为上面的chartResize方法增加节流
methods: {
...
//绑定上节流方法
chartResize: throttle(function () {
this.myChart.resize()
console.log('重置大小')
}, 2000)
}
复制代码
4、效果 (节流版本)
???什么东西,为什么只有最后一个图表重置大小了,其它没变化??
5、分析原因
节流确实生效了,问题是什么?
因为在一个页面内使用了多次这个组件,由于节流是异步
的, 暂时只能记录最后一个组件对象
所以只会响应resize
最后一个
6、解决方法
其实我们更优的方法,应该把监听窗口事件(
window.addEventListener('resize', fn)
)抽离到最外层,而不是在组件内
我的思路-使用vuex
1、在全局中监听
window.addEventListener('resize', fn)
,套上节流。
2、把监听到的窗口大小存在vuex
内
3、在我们的chartCompnent.vue
组件中监听vuex
的窗口大小
7、最终效果
加了节流之后,会顺畅很多
8、部分优化代码,vuex,onResize提取
vuex-window模块
新建vuex的window模块,用来存放页面的宽高。
const window = {
state: {
//页面的宽高
innerWH: {}
},
mutations: {
SET_INNER_WH(state, val) {
//state.innerWH = { ...Object.assign(state.innerWH, val) }
state.innerWH = val
}
},
actions: {
setInnerWH({ commit }, val) {
commit('SET_INNER_WH', val)
}
}
}
export default window
复制代码
main.js内引入的监听onResize.js文件
全局监听窗口大小,并且存入vuex
onResize.js
import { throttle } from './tool'//节流方法
//vuex对象
import store from '@/store/index'
const windowFn = throttle(
function () {
let innerWH = {
innerWidth: window.innerWidth,
innerHeight: window.innerHeight
}
store.dispatch('setInnerWH', innerWH)
},
1000,
{ leading: false }
)
//全局监听窗口大小变化事件
window.addEventListener('resize', windowFn)
复制代码
组件内的监听vuex内数据-chartComponent
chartComponent
//监听vuex内的窗口大小
watch: {
innerWH: {
handler() {
console.log('窗口resize')
this.myChart.resize()
},
deep: true
}
}
复制代码
9、总结思路
全局监听窗口大小, 把窗口大小存在
vuex
内 ,节流在这里加上。
在echarts
组件中监听vuex
内的窗口大小,从而响应图表大小