場景
很多時候我們會在繪制echarts
圖表時,使用以下方法監聽瀏覽器尺寸變化,讓圖表resize()
完成自適應
window.addEventListener('resize', ()=>{wordCloudChart.resize()
})
然后,這種自適應真的足夠周全嘛?有些時候,比如在B端,經常會有側邊欄的寬度變化影響我們工作區各種div的尺寸自動變化,如果淡村使用addEventListener
,那么圖表是不會resize()
的,問題就出現了。這時候就迫切地需要echarts
能夠隨父容器尺寸變化而響應式調整自身尺寸
解決方案 - ResizeObserver API
瀏覽器提供的這個API可以監聽指定單個element
元素的尺寸變化,并在變化時觸發對應的回調函數,借此我們可以來監聽父容器尺寸變化從而觸發resize()
舉個例子
<el-col :span="9" class="chartContainer" id="wc"><div class="title">詞云</div><div id="wordCloud" class="grid-content bg-purple card" ref="wordCloud"></div>
</el-col>
wordCloud.setOption(wcOptions)
const watchChartWc = new ResizeObserver(() => {wordCloud.resize()
})// 使用observe開啟監聽, onObserve可以取消監聽
watchChartWc.observe(document.getElementById('wc'))
ResizeObserver.observe()
接受兩個參數,第一個是指定的單個element
, 第二個是options
但是, 這又會遇到一個問題, 當頁面中同時存在多個圖表時,側邊欄寬度變化引起每個圖表resize()
時,頁面性能會嚴重下降, 側邊欄的動畫會出現特別明顯的卡頓。解決方法是:?防抖
所以完整的版本應當為:
wordCloud.setOption(wcOptions)
const watchChartWc = new ResizeObserver(() => {debounce(() => { wordCloud.resize() }, 300)
})// 使用observe開啟監聽, onObserve可以取消監聽
watchChartWc.observe(document.getElementById('wc'))
其中debounce()
為自己封裝并引入的防抖函數
性能優化
若一個頁面中有多個圖表,且它們會因為同一個原因resize()
,比如上面說的,B端中側邊欄寬度變化帶來的圖表父容器寬度變化從而引起圖表resize()
,多個圖表都只因為這個原因觸發resize()
,那么這時候就不應該創建多個ResizeObserver
去分別監聽每個圖表的父容器, 否則就算防抖,展開會收起側邊欄時,頁面仍然會出現肉眼可見的明顯卡頓。這種情況下,因為每個父容器都是隨著頁面最大的div
變化而變化的,所以這時候應該用ResizeObserver
去監聽頁面最大的div
。這種方法下,肉眼可見的卡頓消失了,非常絲滑.
頁面結構大致如下
<template><div id="container"><div> ... </div></div>
</template>
注意:這種情況下要異步操作,在所有圖表都渲染完畢后,再開啟監聽
const watchCharts = new ResizeObserver(() => {debounce(() => { wordCloud.resize()userChart.resize()courseChart.resize()// ...}, 300)
})// 使用observe開啟監聽, onObserve可以取消監聽
watchCharts.observe(document.getElementById('container'))
寫在最后
如果父容器是自適應的, 那么使用了ResizeObserver
就不需要再使用window.addEventListener('resize', ()=>{})
最后請不要忘記在頁面銷毀前調用unobserve()
取消ResizeObserver
的監聽:
watchChartWc.unobserve(document.getElementById('wc'))
關于ResizeObserver更多請看MDN - ResizeObserver