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

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

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

遠(yuǎn)古方案:resize的弊端

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

完善的第三方庫(kù)——element-resize-detector

element-resize-detector 的底層原理是通過在目標(biāo)元素內(nèi)部創(chuàng)建隱藏的 <object> 或監(jiān)聽滾動(dòng)事件來間接檢測(cè)尺寸變化‌,從而規(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`);
    // 實(shí)際項(xiàng)目中此處可調(diào)用ECharts、HighCharts等圖表庫(kù)的重繪方法
}

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

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

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

具體步驟:

  • 初始化監(jiān)聽事件和初始的尺寸
  • 注入滾動(dòng)元素
  • 注冊(cè)監(jiān)聽:registerListenersAndPositionElements里監(jiān)聽了渲染、收縮、擴(kuò)展事件
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);
}

對(duì)象(object)策略

將一個(gè)隱藏的 <object> 標(biāo)簽嵌入目標(biāo)元素內(nèi)部,并指向當(dāng)前頁面。<object> 元素會(huì)自動(dòng)填充其容器,當(dāng)容器尺寸變化時(shí),<object> 會(huì)觸發(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);
}

對(duì)比:

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

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

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

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

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

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

支持批量處理與資源清理

  • observe(element):開始監(jiān)聽指定元素。
  • unobserve(element):停止監(jiān)聽某個(gè)元素。
  • 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文件。

簡(jiǎn)單的封裝:

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();
  }
}

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

使用方式:

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

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

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    js CSS操作方法集合

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

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

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

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

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

最新評(píng)論

武宁县| 长汀县| 兰考县| 达日县| 黄冈市| 勐海县| 青龙| 甘泉县| 天峻县| 喜德县| 临武县| 若羌县| 乌拉特中旗| 湘潭县| 酒泉市| 封丘县| 利川市| 苗栗市| 邵东县| 游戏| 莒南县| 翁牛特旗| 甘肃省| 靖边县| 西丰县| 永德县| 哈巴河县| 二连浩特市| 建宁县| 子洲县| 香港| 南充市| 永福县| 丹阳市| 苏尼特右旗| 丽水市| 吕梁市| 峨山| 奉新县| 无为县| 玛沁县|