背景:項目有用到 vue-echarts, 百度推出的 vue 版本的 Echarts,圖表自帶響應式屬性 auto-resize, 來實現窗口尺寸變化時,圖表的尺寸自適應,但是發現它是靠監聽 window 的 onresize 來實現的,而有時候當chart 容器 尺寸變化時,window 窗口大小是不變的,比如我這次遇到的,側邊菜單欄的顯示隱藏切換,導致內容區域整體部分寬度會變化,但是window 沒有變化,所以auto-resize 不能監聽這種情況來實現 resize。
解決思路:
一、能否模擬監聽普通 dom 的尺寸變化,然后調用 echarts 的 resize 事件
具體做法有以下幾種:
- 初始化項目后,輪詢,反復查看 dom 尺寸是否變化,這種一聽就感覺不好,開銷太大。
- 監聽元素的滾動事件,在 目標 dom 里面包裹一個同等大小的 div,是隱藏不可見的,當目標 dom 大小變化時,觸發滾動事件。參考文章
- 通過 MutationObserver 監聽dom 節點變化,MutationObserver 是在DOM4規范中定義的,它的前身是 MutationEvent 事件,該事件最初在 DOM2 事件規范中介紹,到來了 DOM3 事件規范中正式定義,但是由於該事件存在兼容性以及性能上的問題被棄用;可以用它來監聽 dom style 的變化, demo 代碼,文檔
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="demo" style="background: blue; height: 200px; width: 100%">
demo 內容
</div>
<script>
var observer = new MutationObserver(function (mutations, observer) {
mutations.forEach(function (mutation) {
console.log(mutation);
});
});
var config = {
attributes: true,
attributeOldValue: true,
attributeFilter: [
'style'
]
};
var el = document.getElementById('demo');
observer.observe(el, config);
</script>
</body>
</html>
- Ie9-10 默認支持 div 的 resize 事件,可以直接通過 div.attachEvent('onresize', handler); 的方式實現;其它瀏覽器,通過在 div 中添加一個內置 object 元素實現監聽,設置 object 元素的 style 使其填充滿 div,這樣當 div 的 size 發生變化時,object 的 size 也會發生變化,然后監聽 object 元素的 contentDocument.defaultView(window對象)的 resize 事件。參考文章
二、vue 實現方案
斟酌了上面幾種方案后,結合具體案例,我覺得還是用 vuex 寫全局數據更好更方便一些,具體步驟如下
- 側邊欄展開和隱藏按鈕點擊 - 觸發事件 - 修改 store - ,在圖表組件里面 watch store 的變化,然后執行 resize 函數。
- 關於 resize(), 因為vue-echarts 插件已經是對 echarts 的封裝,如果不修改它的代碼的話,可以通過 this.$ref 訪問子組件的實例,調用它的 resize()。文檔
// 注意的坑,1.要設置 width 2. width 變化有延遲,需要加個 timeout,不然看不到效果
this.$refs.chart.resize({width: this.$refs.chart.offsetWidth})