ResizeObserver API使用示例詳解
API介紹
當我們需要知道一個元素的大小變化或者屏幕橫豎屏時,我們需要監聽window.resize事件或者window.orientationchange方法。由於reize事件會在一秒內觸發將近60次,所以很容易在改變窗口大小時導致性能問題。換句話說,window.resize事件通常是浪費的,因為它會監聽每個元素的大小變化(隻有window對象才有resize事件),而不是具體到某個元素的變化。如果我們隻想監聽某個元素的變化的話,這種操作就很浪費性能瞭。
而ResizeObserver API就可以幫助我們:監聽一個DOM節點的變化,這種變化包括但不僅限於:
- 某個節點的出現和隱藏
- 某個節點的大小變化
ResizeObserver API是一個新的JavaScript API,與IntersectionObserver API非常相似,它們都允許我們去監聽某個元素的變化。
實際上,ResizeObserver API使用瞭觀察者模式,也就是我們常說的發佈-訂閱模式。發佈-訂閱模式是JavaScript中典型的設計模式,在很多地方都有使用到。如Nodejs的Event模塊,Vue的父子組件通信等等。對發佈-訂閱模式不熟悉的同學可以看看《JavaScript設計模式與開發實踐》這本書,對Vue的通信感興趣的可以看看Vue官網啦。
所以呢,我個人認為,ResizeObserver API的出現是用於替代window.resize方法糟糕的性能的。(不喜親噴: ()
瀏覽器兼容性
雖然可以用來替代resize事件。但是它,很新,新到隻有部分瀏覽器支持。
但是不要慫呀,如果想使用它,可以使用其polyfill。最低可以兼容到IE8以上的瀏覽器啦。所以以後在開發過程中如果想使用resize事件監聽DOM的大小變化時,何不嘗試一下ResizeObserver API呢?
用法
使用ResizeObserver API非常簡單。ResizeObserver是個構造函數。在使用new關鍵字調用構造函數,返回實例對象時,需要傳入一個回調函數,這個回調用於監聽實例對象某個DOM節點的變化。如
const myObserver = new ResizeObserver(entries => { entries.forEach(entry => { console.log('大小位置', entry.contentRect) console.log('監聽的DOM', entry.target) }) }) myObserver.observe(document.body)
以上,調用實例對象的observe方法,監聽整個body節點的變化,當改變窗口大小或者某個DOM節點出現或隱藏時時,就會觸發回調。
觸發回調後的第一個參數是一個ResizeObserverEntry對象。這裡的entry.target是DOM節點本身,而entry.contentRect是一個對象,包含瞭節點的位置屬性,如width, height, left, right, bottom, left, x, y等。
width
:指元素本身的寬度,不包含padding,border值
height
:指元素本身的高度,不包含padding,border值
top
:指padidng-top的值
left
:指padding-left的值
right
:指left + width的值
bottom
: 值top + height的值
x
:大小與top相同
y
:大小與left相同,不知道具體是指什麼
明白瞭contentRect之後,就可以在使用這個api的時候針對不同場景獲取不同的值進行業務的開發。
接著,如果想在監聽多個DOM節點的變化,直接在一個實例對象上調用多次observe方法就好瞭。如
const myObserver = new ResizeObserver(entries => { // 註意,entres是個數組,數組項為每個需要監聽的DOM節點 entries.forEach(entry => { console.log('大小位置 contentRect', entry.contentRect) console.log('監聽的DOM target', entry.target) }) }) myObserver.observe(document.body) myObserver.observe(document.querySelector('#app'))
然後,實例對象myObserver方法除瞭有observe方法之外,還有disconnect方法和unobserve方法。
unobserve方法,顧名思義瞭,就是取消監聽某個DOM節點。比如說想在兩秒後取消監聽document.body,那麼這樣做就好瞭
window.setTimeout(() => { myObserver.unobserve(document.body) // 需要接收一個參數 }, 2000)
disconnect方法呢,就是取消對所有節點的監聽。比如說想在四秒後取消監聽所有節點,那麼
window.setTimeout(() => { myObserver.disconnect() // 此時就不會再監聽document.body,和#app節點瞭 }, 4000)
最後,在使用ResizeObserver API的時候,在每次觸發元素的大小變化時,會在1s內觸發回調蠻多次的。如果想進一步優化性能,可以加上throttle節流函數處理
// throttle需要自行引入哈 const myObserver = new ResizeObserver(throttle(entries => { entries.forEach(entry => { console.log('大小位置 contentRect', entry.contentRect) console.log('監聽的DOM target', entry.target) }) }), 500)
這樣子就能做到每個500ms觸發一次回調啦。是不是很勁(粵語)
總結
好的,關於ResizeObserver API的介紹就到這裡瞭,如果想要一個更加具體的例子,可以參考
JavaScript API ResizeObserver使用示例
https://github.com/que-etc/resize-observer-polyfill
更多關於ResizeObserver API使用的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- JavaScript API ResizeObserver使用示例
- ResizeObserver 監視 DOM大小變化示例詳解
- 可視化埋點平臺元素曝光采集intersectionObserver思路實踐
- 原生JS Intersection Observer API實現懶加載
- 利用原生JS實現懶加載lazyLoad的三種方法總結