響應式網站/Web應用程序 根據視口大小調整內容展現方式。這一般經過CSS和media查詢來完成。當CSS表現很差咱們會使用Javascript。git
好比document.addEventListener("resize",fun)或者Element的onresize屬性。經過監聽window.resize事件,Javascript DOM操做與視口大小保持同步。github
但你會意識到,這甚至不包括在窗口未被調整大小但元素改變其大小的狀況。例如,添加新的子元素,設置元素的display樣式none或相似的操做會改變元素,其兄弟或祖先的大小。web
隨着響應式Web應用程序的普及,對響應式組件的需求也會增長。這些組件也須要有對resize事件作出響應。不幸的是,Web平臺目前不提供組件跟蹤其大小的方法。canvas
一些應用程序實施自制的調整大小通知框架(例如:Polymer)。這種方法容易出錯,難以維護,而且須要每一個組件都實施自制方法。數組
其餘人巧妙的經過能夠代替調整事件的事件來調整內容(例如:<a href="https://github.com/wnr/element-resize-detector">element-resize-detector</a>)。目前最優秀的方法都使用相似的技巧:框架
在組件中插入一個絕對定位的子項,而且以發出滾動事件的方式製做子項,或者在父項大小更改時製做window.resize。ide
絕對定位的子項方法在ShadowDOM或React等框架中不起做用。函數
這些方法都不可取。它們在正確性,代碼複雜性和性能方面都失敗了。post
在當今的Web平臺上沒法複製ResizeObserver功能。性能
這就是爲何ResizeObserver是一個有用的原始API。它對任何觀察到的元素的大小的變化做出反應,與致使變化的緣由無關。它還爲您提供訪問觀察元素的新大小。
API
提到的「Observer」後綴的API共享一個簡單的API設計。ResizeObserver也不例外。
您建立一個ResizeObserver 對象並將回調傳遞給構造函數。回調將被賦予一個數組ResizeOberverEntries- 每一個觀察元素一個條目 - 包含元素的大小
var ro = new ResizeObserver( entries => { for (let entry of entries) { const cr = entry.contentRect; console.log('Element:', entry.target); console.log(`Element size: ${cr.width}px x ${cr.height}px`); console.log(`Element padding: ${cr.top}px ; ${cr.left}px`); } }); // Observe one or multiple elements ro.observe(someElement);
如下是使用ResizeObserver在畫布內繪製橢圓的示例。
<canvas style="width:10%;height:10%"></canvas> <canvas style="width:20%;height:20%"></canvas> function drawEllipse(entry) { let ctx = entry.target.getContext('2d'); let rx = Math.floor(entry.contentRect.width / 2); let ry = Math.floor(entry.contentRect.height / 2); ctx.beginPath(); ctx.clearRect(0,0, entry.contentRect.width,entry.contentRect.height); ctx.ellipse(rx, ry, rx, ry, 0, 0, 2 * Math.PI); ctx.stroke(); } // ResizeObserver delegates action to Element's handleResize method let ro = new ResizeObserver( entries => { for (let entry of entries) { if (entry.target.handleResize) entry.target.handleResize(entry); } }); // Set up observations var canvases = document.querySelectorAll('canvas'); for (let canvas of canvases) { canvas.handleResize = drawEllipse; ro.observe(canvas); }
內聯框架能夠檢測其大小什麼時候發生變化,並通知父窗口。
let ro = new ResizeObserver(entries => { let idealSize = computeIdealSize(); window.parent.postMessage({ name: "iframeResize", width: idealSize.width, height: idealSize.height }, '*'); }); ro.observe(document.body);
當新消息到達時,咱們如何讓聊天窗口滾動到底部?ResizeObserver解決方案將全部消息保存在不斷增加的中div,並觀察其大小。當新消息到達時,滾動到底部。
完整的例子 詳細討論了用戶滾動的處理。
.chat { overflow: scroll; } <div class="chat"> <!-- chat has the scrollbar --> <div class="chat-text"> <!-- chat-text contains chat text --> <div>jack: hi </div> <div>jill: hi </div> </div> </div let ro = new ResizeObserver( entries => { for (let e of entries) { let chat = e.target.parentNode; chat.scrollTop = chat.scrollHeight - chat.clientHeight; } }); ro.observe(document.querySelector('.chat-text'))
How
Performance
調整通知的大小能夠有很高的頻率。Observer API避免了事件捕獲/泡泡的開銷。
框架做者能夠在ResizeObserver之上提供一個開發友好的「基於事件」的API,以免註冊太多的觀察者。
Notice
當多個ResizeObservers註冊時,通知應按註冊順序傳送。
回調變動集應按註冊順序列出元素。
內聯元素不該該生成調整大小通知。
轉換不會影響內容大小。他們不該該觸發通知。
影響內容大小的動畫應該會觸發通知。
若是工做成本很高,開發人員可能會但願在動畫期間跳過工做。
當元素不可見時,內容大小變爲0。這將生成一個調整大小的通知。開發人員將可以使用ResizeObserver觀察可見性。
本文參考:
ResizeObserver: It’s Like document.onresize for Elements ----- https://developers.google.com/web/updates/2016/10/resizeobserver
WICG/ResizeObserver ----- https://github.com/WICG/ResizeObserver/blob/master/explainer.md