使用ResizeObserver對單個元素進行大小監聽

一、API介紹

ResizeObserver

這是一個能針對某個元素實行大小、位置變化監聽的API,是一個類,它提供了一個觀察器,該觀察器將在每個 resize 事件上調用,目前chrome、safari、fireFox(pc)基本支持。

二、常規用法

const resizeOb= new ResizeObserver(entries => {
    for(const entry of entries) {
        console.log(entry)
    }
})
resizeOb.observe(document.getElementById("test"))

//打印結果
//{target: div#test, contentRect: DOMRectReadOnly}

通過實例化一個監聽器,然後調用observe方法傳入一個要執行監聽的DOM元素或SVG元素,那麼每次resize事件觸發時都會執行ResizeObserver實例化時傳入的回調函數,改回調函數默認會返回一個數組,數組裏包含了每個被執行了監聽器的元素及其可讀信息,元素的拜訪順序也是監聽器執行的順序(對,實例化一個監聽器,可多次執行observe方法對不同元素進行監聽!)

三、在react+typescript中使用

如果簡單對某個元素監聽的話,其實就像上面的例子那樣調用就可以了。但是如果像在react hookstypescript的加持下使用,還需要額外注意:

  • 在hook中,依然需要在useEffect裏使用,因爲observe方法需要傳入一個有效DOM
  • 該監聽器其實也是副作用,理應在組件銷燬時取消副作用,比如在useEffect裏返回一個函數用於銷燬副作用
  • typescript中目前不能識別該API,至少筆者的版本(3.7.5)是這樣,需要自己編寫聲明文件。

使用示例如下:

useEffect(() => {
       const resizeObserver = new ResizeObserver((entries) => {console.log(entries)});
        resizeObserver.observe(document.getElementById("test"))
        return (): void => { resizeObserver.unobserve(document.getElementById("test")) };
    }, []);

如果是create-react-app腳手架搭建的項目,還需要在react-app-env.d.ts中加上該ResizeObserver的聲明,如果是其他typescript項目,則需要在全局global中聲明:

// 關於元素的只讀信息
interface DOMRectReadOnly {
    bottom:number;
    height:number;
    left:number;
    right:number;
    top:number;
    width:number;
    x:number;
    y:number;
}
//監聽器回調函數中的參數類型,自帶元素本身(target)與對應的只讀位置、大小信息(contentRect)
interface ResizeObserverEntry {
    target: HTMLElement | null;
    contentRect: ResizeObserverEntry["target"] extends null? null : DOMRectReadOnly
}
// 監聽器構造函數所需要傳入的回調函數
type EntriesFuntion = (entries:Array<ResizeObserverEntry>)=>void;
/**
 * 元素大小、位置變化監聽器
 */
declare class ResizeObserver {
    /**
     * 元素大小、位置變化監聽器
     * @param entriesFn 關於掛載到監聽器的回調函數
     * @returns {Observer} 返回一個監聽器對象
     */
    constructor(entriesFn:EntriesFuntion): ResizeObserver{};
    /**
     * 執行目標元素的監聽
     * @param target 要執行監聽的目標元素
     * @param options 設置元素的盒子模型,默認爲content-box
     * @returns {void}
     */
    observe(target:HTMLElement|null,options?:{box:'border-box'|"content-box"}):void;

    /**
     * 取消目標元素的監聽
     * @param target 要取消執行監聽的目標元素
     * @returns {void}
     */
    unobserve(target:HTMLElement|null):void

    /**
     * 取消所有元素監聽
     */
    disconnect():void
}

四、結語

ResizeObserver是在resize的過程中調用的,resize本身屬於頻繁觸發的事件,在期間穿插太多邏輯其實對性能影響較大,如果只是想對某個元素變動後執行某個回調的話,建議最好搭配函數節流進行使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章