一、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元素,那麼每次resiz
e事件觸發時都會執行ResizeObserver
實例化時傳入的回調函數,改回調函數默認會返回一個數組,數組裏包含了每個被執行了監聽器的元素及其可讀信息,元素的拜訪順序也是監聽器執行的順序(對,實例化一個監聽器,可多次執行observe
方法對不同元素進行監聽!)
三、在react+typescript中使用
如果簡單對某個元素監聽的話,其實就像上面的例子那樣調用就可以了。但是如果像在
react hooks
和typescript
的加持下使用,還需要額外注意:
- 在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
本身屬於頻繁觸發的事件,在期間穿插太多邏輯其實對性能影響較大,如果只是想對某個元素變動後執行某個回調的話,建議最好搭配函數節流進行使用。