最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript監(jiān)聽DOM尺寸變化的解決方案

 更新時間:2026年05月22日 08:26:27   作者:親親小寶寶鴨  
文章分析了傳統(tǒng)resize監(jiān)聽的弊端,如粒度粗糙、性能問題等并提出了多種解決方案,通過插入<object>、監(jiān)聽scroll或使用現(xiàn)代的ResizeObserver API等來實現(xiàn)了更精準、高效地的元素尺寸監(jiān)聽,文章還討論了這些方法的優(yōu)缺點及適用場景,需要的朋友可以參考下

遠古方案:resize的弊端

  1. 全局監(jiān)聽,粒度粗糙window.resize 是全局事件,任何窗口尺寸變化都會觸發(fā)回調(diào),即使頁面中目標元素并未發(fā)生實際變化。開發(fā)者需手動遍歷并比對所有關(guān)注元素的尺寸,邏輯冗余且效率低下。
  2. 頻繁觸發(fā),易導(dǎo)致性能瓶頸‌ 用戶拖拽調(diào)整窗口時,resize 事件會高頻連續(xù)觸發(fā),若回調(diào)中包含復(fù)雜計算或 DOM 操作,極易引發(fā)頁面卡頓。雖可通過節(jié)流(throttle)優(yōu)化,但仍無法從根本上解決問題。
  3. 無法感知非窗口引起的元素變化‌ 當元素因內(nèi)容更新、CSS 動畫、父容器結(jié)構(gòu)調(diào)整等非窗口 resize 行為導(dǎo)致尺寸變化時,該事件完全無法捕獲,存在嚴重的監(jiān)聽盲區(qū)。

下面這段代碼,是舊版本的vben-admin封裝的echarts的hooks,使用了監(jiān)聽window.resize的方式監(jiān)聽屏幕尺寸變化,從而去重新渲染echarts圖表:

 function initCharts(t = theme) {
    const el = unref(elRef);
    if (!el || !unref(el)) {
      return;
    }

    chartInstance = echarts.init(el, t);
    const { removeEvent } = useEventListener({
      el: window,
      name: 'resize',
      listener: resizeFn,
    });
    removeResizeFn = removeEvent;
    const { widthRef, screenEnum } = useBreakpoint();
    if (unref(widthRef) <= screenEnum.MD || el.offsetHeight === 0) {
      useTimeoutFn(() => {
        resizeFn();
      }, 30);
    }
  }

可見大部分人的第一想法還是用resize這個深入人心的方案。

完善的第三方庫——element-resize-detector

element-resize-detector 的底層原理是通過在目標元素內(nèi)部創(chuàng)建隱藏的 <object> 或監(jiān)聽滾動事件來間接檢測尺寸變化‌,從而規(guī)避瀏覽器無法原生監(jiān)聽元素 resize 的限制。

使用方式:

import elementResizeDetectorMaker from "element-resize-detector";
const erd = elementResizeDetectorMaker();

const chartContainer = document.getElementById("chartContainer");

// 模擬圖表繪制函數(shù)
function renderChart(width, height) {
    console.log(`重新繪制圖表:寬${width}px,高${height}px`);
    // 實際項目中此處可調(diào)用ECharts、HighCharts等圖表庫的重繪方法
}

// 監(jiān)聽元素尺寸變化 回調(diào)函數(shù)里重繪
erd.listenTo(chartContainer, function(element) {
    const width = element.offsetWidth;
    const height = element.offsetHeight;
    renderChart(width, height);
})

具體實現(xiàn)依賴兩種核心策略:

  1. 滾動(scroll)策略(默認) ‌ 在目標元素內(nèi)動態(tài)插入一個隱藏的 <div>,并設(shè)置其寬高略大于父元素,同時監(jiān)聽該元素的 scroll 事件。當目標元素尺寸發(fā)生變化時,內(nèi)部元素的可滾動區(qū)域隨之改變,從而觸發(fā) scroll 事件,實現(xiàn)對尺寸變化的捕獲。該方式性能高、兼容性好,適用于絕大多數(shù)現(xiàn)代瀏覽器。

具體步驟:

  • 初始化監(jiān)聽事件和初始的尺寸
  • 注入滾動元素
  • 注冊監(jiān)聽:registerListenersAndPositionElements里監(jiān)聽了渲染、收縮、擴展事件
getState(element).onRendered = handleRender;
getState(element).onExpand = handleScroll;
getState(element).onShrink = handleScroll;
function install() {
  initListeners();
  storeStartSize();

  batchProcessor.add(0, storeStyle);
  batchProcessor.add(1, injectScrollElements);
  batchProcessor.add(2, registerListenersAndPositionElements);
  batchProcessor.add(3, finalizeDomMutation);
  batchProcessor.add(4, ready);
}

對象(object)策略

將一個隱藏的 <object> 標簽嵌入目標元素內(nèi)部,并指向當前頁面。<object> 元素會自動填充其容器,當容器尺寸變化時,<object> 會觸發(fā)自身的 resize 事件。由于 <object> 支持監(jiān)聽 resize,因此可借此間接感知父元素的尺寸變化。此方法主要用于兼容老舊瀏覽器(如 IE)。

核心邏輯:

// IE8 直接給元素綁定resize事件
if(browserDetector.isIE(8)) {
  //IE 8 does not support object, but supports the resize event directly on elements.
  getState(element).object = {
    proxy: listenerProxy
  };
  element.attachEvent("onresize", listenerProxy);
} else {
  var object = getObject(element);
  if(!object) {
    throw new Error("Element is not detectable by this strategy.");
  }
  object.contentDocument.defaultView.addEventListener("resize", listenerProxy);
}

對比:

策略名稱優(yōu)點缺點
object精確性高性能相對差,尤其是同一個頁面有多個元素需要監(jiān)聽時
scroll性能較好精確性較低、特定布局無法使用(源碼中有大量的兼容性處理)

現(xiàn)代瀏覽器的處理方案——resizeObserver——以及簡單的封裝

ResizeObserver‌ 是現(xiàn)代瀏覽器提供的原生 API,用于‌監(jiān)聽 DOM 元素內(nèi)容區(qū)域的尺寸變化‌,無需依賴輪詢或事件冒泡,具有高精度、高性能的特點。

精準監(jiān)聽元素級尺寸變化
ResizeObserver 能直接監(jiān)聽任意 DOM 元素的 content-box 或 border-box 尺寸變化,包括由 CSS 動畫、內(nèi)容更新、布局重排等引起的改變,‌無需手動計算或依賴窗口 resize 事件‌。

異步回調(diào),避免性能瓶頸
回調(diào)函數(shù)通過 requestAnimationFrame 異步執(zhí)行,不會阻塞渲染線程,即使在高頻變化場景下也能保持頁面流暢。

自動忽略不可見元素
對于 display: none 或未插入文檔的元素,ResizeObserver 會自動暫停監(jiān)聽,減少無效計算。

支持批量處理與資源清理

  • observe(element):開始監(jiān)聽指定元素。
  • unobserve(element):停止監(jiān)聽某個元素。
  • disconnect():斷開所有監(jiān)聽,釋放資源。

使用方式:

const observer = new ResizeObserver((entries) => {
  entries.forEach((entry) => {
    const { width, height } = entry.contentRect; // content-box 尺寸
    console.log(`內(nèi)容區(qū)域尺寸:${width}x${height}`);
  });
});

// 開始監(jiān)聽
observer.observe(document.getElementById('target'));

兼容性問題:

resizeObserver的瀏覽器支持情況如下:

Chrome: 從版本 64 開始支持(2018 年 1 月發(fā)布)

Firefox: 從版本 69 開始支持(2019 年 9 月發(fā)布)

Edge: 從版本 79 開始支持(2020 年 1 月發(fā)布)

Safari: 從版本 13.1 開始支持(2020 年 3 月發(fā)布)

Opera: 從版本 51 開始支持(2018 年 1 月發(fā)布)。

若需要支持更低版本的瀏覽器,需要引用polyfill文件。

簡單的封裝:

import ResizeObserver from 'resize-observer-polyfill';

function resizeHandler(entries: any[]) {
  for (const entry of entries) {
    const listeners = entry.target.__resizeListeners__ || [];
    if (listeners.length) {
      listeners.forEach((fn: () => any) => {
        fn();
      });
    }
  }
}

export function addResizeListener(element: any, fn: () => any) {
  if (!element.__resizeListeners__) {
    element.__resizeListeners__ = [];
    element.__ro__ = new ResizeObserver(resizeHandler);
    element.__ro__.observe(element);
  }
  element.__resizeListeners__.push(fn);
}

export function removeResizeListener(element: any, fn: () => any) {
  if (!element || !element.__resizeListeners__) return;
  element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
  if (!element.__resizeListeners__.length) {
    element.__ro__.disconnect();
  }
}

上面的封裝是為了處理同一個元素多次監(jiān)聽,避免造成監(jiān)聽的覆蓋。封裝之后,用法和addEventListener比較相似,只是無需傳入事件類型。

使用方式:

const chartContainer = document.getElementById("chartContainer");

// 模擬圖表繪制函數(shù)
function renderChart() {
    console.log(`重新繪制圖表`);
    // 實際項目中此處可調(diào)用ECharts、HighCharts等圖表庫的重繪方法
}

// 監(jiān)聽元素尺寸變化 回調(diào)函數(shù)里重繪
addResizeListener(chartContainer, function() {
    renderChart()
})

以上就是JavaScript監(jiān)聽DOM尺寸變化的解決方案的詳細內(nèi)容,更多關(guān)于JavaScript監(jiān)聽DOM尺寸變化的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 前端JS如何創(chuàng)建一個可隨時取消的定時器

    前端JS如何創(chuàng)建一個可隨時取消的定時器

    這篇文章主要為大家詳細介紹了前端JavaScript如何創(chuàng)建一個可隨時取消的定時器,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-08-08
  • JS?中數(shù)組的增刪改查和對象的增刪改查實例詳解

    JS?中數(shù)組的增刪改查和對象的增刪改查實例詳解

    這篇文章主要介紹了JS?中數(shù)組的增刪改查和對象的增刪改查實例詳解,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • JavaScript異步編程之Promise的初步使用詳解

    JavaScript異步編程之Promise的初步使用詳解

    這篇文章主要介紹了JavaScript異步編程之Promise的初步使用,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • JavaScript防止重復(fù)提交的三種解決方案

    JavaScript防止重復(fù)提交的三種解決方案

    防止JavaScript重復(fù)點擊和提交需結(jié)合前端禁用按鈕、節(jié)流和標志位,這篇文章主要介紹了JavaScript防止重復(fù)提交的三種解決方案,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-07-07
  • JavaScript文件的操作方法總結(jié)大全

    JavaScript文件的操作方法總結(jié)大全

    在JavaScript中,我們可以通過文件操作來讀取和寫入文件,文件操作是Web開發(fā)中常見的任務(wù)之一,它使我們能夠處理本地文件、上傳文件以及與服務(wù)器進行文件交互,這篇文章主要介紹了JavaScript文件的操作方法的相關(guān)資料,需要的朋友可以參考下
    2026-05-05
  • JavaScript程序員應(yīng)該知道的45個實用技巧

    JavaScript程序員應(yīng)該知道的45個實用技巧

    在這篇文章中,我將分享一組JavaScript的技巧、竅門和最佳實踐,這些都是JavaScript程序員應(yīng)該知曉的,不管他們是使用在瀏覽器/引擎上,還是服務(wù)器端(SSJS——Service Side JavaScript)JavaScript解釋器上
    2014-03-03
  • JavaScript關(guān)于提高網(wǎng)站性能的幾點建議(一)

    JavaScript關(guān)于提高網(wǎng)站性能的幾點建議(一)

    這篇文章主要介紹了JavaScript關(guān)于提高網(wǎng)站性能的幾點建議(一)的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-07-07
  • js CSS操作方法集合

    js CSS操作方法集合

    用js實現(xiàn)的對css的一些操作方法,集合,方便需要用js控制css的朋友
    2008-10-10
  • 在TypeScript中將unknown類型轉(zhuǎn)換為更具體的類型

    在TypeScript中將unknown類型轉(zhuǎn)換為更具體的類型

    本文介紹了TypeScript中unknown類型的使用,以及如何將unknown類型安全地轉(zhuǎn)換為更具體的類型,本文詳細介紹了類型斷言、內(nèi)置類型守衛(wèi)和自定義類型守衛(wèi)的使用方法,并提供了最佳實踐建議,以確保代碼的類型安全性和可維護性,需要的朋友可以參考下
    2026-04-04
  • 詳解JavaScript實現(xiàn)動態(tài)的輪播圖效果

    詳解JavaScript實現(xiàn)動態(tài)的輪播圖效果

    這篇文章主要介紹了JavaScript實現(xiàn)動態(tài)的輪播圖效果,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評論

门头沟区| 东城区| 滨海县| 台东市| 盐边县| 舟曲县| 彰武县| 新巴尔虎左旗| 潞城市| 光山县| 分宜县| 甘孜县| 永新县| 井冈山市| 泌阳县| 齐齐哈尔市| 高密市| 张家港市| 江北区| 大渡口区| 霞浦县| 屯门区| 大丰市| 澄城县| 长沙市| 金湖县| 紫金县| 香港 | 定安县| 无棣县| 民勤县| 淮阳县| 得荣县| 贺兰县| 永泰县| 南江县| 且末县| 怀来县| 阿荣旗| 杭锦后旗| 武城县|