欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript中5個(gè)重要的Observer函數(shù)小結(jié)

 更新時(shí)間:2024年01月15日 10:35:22   作者:小馬甲丫  
瀏覽器為開(kāi)發(fā)者提供了功能豐富的Observer,本文主要介紹了JavaScript中5個(gè)重要的Observer函數(shù)小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下

一、前言

瀏覽器為開(kāi)發(fā)者提供了功能豐富的Observer,在這篇文章中,我們將深入研究這些常見(jiàn)的瀏覽器 Observer,剖析它們的作用、用法以及它們?cè)?nbsp;Web 開(kāi)發(fā)中的應(yīng)用場(chǎng)景。

二、MutationObserver

MutationObserver用于監(jiān)聽(tīng)DOM對(duì)象的變更(包括子節(jié)點(diǎn)),當(dāng)節(jié)點(diǎn)屬性發(fā)生變化,或執(zhí)行增刪改操作時(shí)執(zhí)行對(duì)應(yīng)的callback

MutationObserver為我們提供了一種十分方便的監(jiān)聽(tīng)DOM變化的方式。

2.1、基本使用

// Observer需要一個(gè)用于監(jiān)聽(tīng)的目標(biāo)DOM
const targetNode = document.getElementById("app");

//用于確定mutation監(jiān)聽(tīng)變化的范圍
const config = { 
  attributes: true, // 監(jiān)聽(tīng)目標(biāo)節(jié)點(diǎn)的屬性變化,例如id,class等屬性
  childList: true, // 除目標(biāo)節(jié)點(diǎn)外還要監(jiān)聽(tīng)目標(biāo)節(jié)點(diǎn)的直接子節(jié)點(diǎn)
  subtree: true,  // subtree的范圍大于childList,還包括子節(jié)點(diǎn)children
  characterData: true   // 監(jiān)聽(tīng)TextNode需要額外配置,默認(rèn)TextNode變化不會(huì)觸發(fā)callback
};

// 當(dāng)觀察到變動(dòng)時(shí)執(zhí)行的回調(diào)函數(shù),mutationsList包含本次變更的信息
const callback = function (mutationsList, observer) {
  console.log(mutationsList)
};

const observer = new MutationObserver(callback);
observer.observe(targetNode, config);

2.2、API介紹

2.2.1、observe

observe用于開(kāi)啟對(duì)某個(gè)DOM的監(jiān)聽(tīng),一個(gè)MutationObserver可以通過(guò)多次調(diào)用observe監(jiān)聽(tīng)多個(gè)DOM的變化。

當(dāng)變化發(fā)生時(shí)MutationObserver會(huì)將一個(gè)或多個(gè)mutation對(duì)象傳給callback的第一個(gè)參數(shù),mutation對(duì)象內(nèi)包含本次變更的相關(guān)信息下面看一下mutation的結(jié)構(gòu)

{
  addedNodes: [],  //新增DOM時(shí)會(huì)包含被新增的DOM
  attributeName: "id",   //本次變更的屬性名
  attributeNamespace: null,  //命名空間URI,一般用不到
  nextSibling: null, //當(dāng)存在添加/刪除節(jié)點(diǎn)的操作時(shí)會(huì)存在nextSibling/previousSibling, 引用上一個(gè)/下一個(gè)兄弟節(jié)點(diǎn)
  previousSibling: null,
  oldValue: null,
  removedNodes: [],
  target: Text,
  type: "characterData" //變更類(lèi)型,如characterData,childList等
}

2.2.2、disconnect

observer.disconnect()

調(diào)用observer.disconnectObserver將不再監(jiān)聽(tīng)target,如果不需要監(jiān)聽(tīng)請(qǐng)及時(shí)調(diào)用該方法,以免產(chǎn)生預(yù)期之外的行為以及內(nèi)存泄漏。

2.2.3、takeRecords

takeRecords用于獲取在事件隊(duì)列中但還未傳遞給callbackmutation對(duì)象,通常使用在調(diào)用disconnect時(shí)又不想丟失之前的mutationRecords(如果mutation連續(xù)觸發(fā),可能出現(xiàn)mutation還在隊(duì)列中但未傳遞給callback的情況)。

2.3、常見(jiàn)場(chǎng)景

對(duì)于需要監(jiān)聽(tīng)DOM變化的場(chǎng)景可考慮使用MutationObserver,利于用于Tag group內(nèi)元素的動(dòng)態(tài)渲染,下面使用MutationObserver實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Todo List

2.3.1、源碼

<!DOCTYPE html>
<html>
<head>
  <title>MutationObserver To-Do List Demo</title>
  <style>
    #todo-list {
      list-style-type: none;
    }
  </style>
</head>
<body>
  <h1>待辦事項(xiàng)列表</h1>

  <ul id="todo-list">
    <li>完成作業(yè)</li>
    <li>購(gòu)物</li>
  </ul>

  <button id="addTask">添加任務(wù)</button>
  <button id="removeTask">移除任務(wù)</button>
  <p id="taskCount">任務(wù)數(shù)量:2</p>

  <script>
    const todoList = document.getElementById('todo-list');
    const taskCount = document.getElementById('taskCount');

    const observer = new MutationObserver((mutationsList, observer) => {
      mutationsList.forEach((mutation) => {
        if (mutation.type === 'childList') {
          updateTaskCount();
        }
      });
    });

    const config = { childList: true };

    observer.observe(todoList, config);

    document.getElementById('addTask').addEventListener('click', () => {
      const newTask = document.createElement('li');
      newTask.textContent = '新任務(wù)';
      todoList.appendChild(newTask);
    });

    document.getElementById('removeTask').addEventListener('click', () => {
      const tasks = todoList.getElementsByTagName('li');
      if (tasks.length > 0) {
        todoList.removeChild(tasks[0]);
      }
    });

    function updateTaskCount() {
      const tasks = todoList.getElementsByTagName('li');
      taskCount.textContent = `任務(wù)數(shù)量:${tasks.length}`;
    }
  </script>
</body>
</html>

2.3.2、預(yù)覽

在線源碼請(qǐng)點(diǎn)擊【前往

2.3.3、效果

三、IntersectionObserver

IntersectionObserver用于監(jiān)聽(tīng)一個(gè)元素的可見(jiàn)比例(一個(gè)DOM元素被另一個(gè)DOM元素遮擋百分比)變化。

3.1、基本使用

const target = document.getElementById('app');

const options = {
  root: rootTarget, // 相對(duì)于某個(gè)元素進(jìn)行遮擋計(jì)算
  rootMargin: '0px', // 進(jìn)行計(jì)算的邊界范圍,通過(guò)rootMargin可以實(shí)現(xiàn)提前計(jì)算或延遲計(jì)算(相對(duì)于root原本尺寸)的效果
  threshold: 0.5 // 觸發(fā)callback時(shí)的遮擋比例,0.5代表元素被遮擋50%時(shí)觸發(fā)callback。由于瀏覽器事件循環(huán)機(jī)制的影響,callback觸發(fā)時(shí)遮擋比例通常不會(huì)是精確的50%。
};

const intersectionObserver = new IntersectionObserver((entries, observer) => {
  //和MutationObserver相同,也是產(chǎn)生一個(gè)array
  entries.forEach(entry => {
    console.log(entry)
  });
}, options);

intersectionObserver.observe(target);

3.2、API介紹

3.2.1、observe & options

observe方法用于啟動(dòng)一個(gè)Observer對(duì)DOM元素的監(jiān)聽(tīng)。在創(chuàng)建IntersectionObserver時(shí)可以通過(guò)傳入option改變監(jiān)聽(tīng)的行為。

const options = {
  root: root, 
  rootMargin: '100px', 
  threshold: 0.7 
};

在上面的配置中,通過(guò)配置rootMargin100pxtarget距離root元素100px時(shí)即可判定為被遮擋,通過(guò)threshold設(shè)置為0.7,當(dāng)遮擋比例查過(guò)70%時(shí)執(zhí)行callback。

3.2.2、entry

callback第一個(gè)paramentry對(duì)象構(gòu)成的array,entry包含了觸發(fā)callback時(shí)DOM的位置信息

//被監(jiān)聽(tīng)DOM元素的Rect信息
boundingClientRect:  {
  bottom: 208
  height: 200
  left: 8
  right: 208
  top: 8
  width: 200
  x: 8
  y: 8
}
intersectionRatio: 1 //交叉比例
// 被監(jiān)聽(tīng)元素與Root元素交叉部分矩形的Rect信息。
intersectionRect: {
  bottom: 208,
  height: 200,
  left: 8,
  right: 208,
  top: 8,
  width: 200,
  x: 8,
  y: 8
},
// 是否處于交叉狀態(tài)
isIntersecting: true,
isVisible: false,
// Root元素的Rect信息
rootBounds:  {
  bottom: 606,
  height: 606,
  left: 0,
  right: 476,
  top: 0,
  width: 476,
  x: 0,
  y: 0
},
// root元素
target: div#target,
time: 49.09999990463257

3.3、常見(jiàn)場(chǎng)景

乍一看IntersectionObserver好像沒(méi)啥用,單這個(gè)Api在某些場(chǎng)景下十分好用。

比如我們有一個(gè)通過(guò)sticky固定在屏幕頂部的header元素,我們希望在觸發(fā)sticky時(shí)給header加一個(gè)shadow(很多table都有這樣的功能)

一種很常見(jiàn)的做法是監(jiān)聽(tīng)scroll,當(dāng)滾動(dòng)一定距離時(shí)加上shadow即可。但是監(jiān)聽(tīng)scroll本身會(huì)早成一定的渲染壓力(scroll觸發(fā)非常頻繁),同時(shí)如果使用React這樣的框架又會(huì)造成額外的render,在用戶的視角看來(lái)更卡了。

此時(shí)使用IntersectionObserver就很合適了,因?yàn)槲覀冃枰O(jiān)聽(tīng)的只是觸發(fā)sticky的一瞬間,其他的滾動(dòng)都是無(wú)效的,沒(méi)必要進(jìn)行計(jì)算。

3.3.1、源碼

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Sticky Header with Shadow on Intersection</title>
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    header {
      height: 80px;
      background-color: #3498db;
      color: white;
      text-align: center;
      line-height: 80px;
      position: sticky;
      top: 0;
      z-index: 100;
    }

    .header-shadow {
      transition: box-shadow 0.3s ease;
    }

    .header-shadow.shadow {
      box-shadow: 0 2px 5px black;
    }

    section {
      height: 1000px;
      background-color: #ecf0f1;
      padding: 20px;
    }
  </style>
</head>
<body>
  <div id="guard"></div>
  <header id="sticky-header" class="header-shadow">Sticky Header</header>

  <section>
    <p>向下滾動(dòng)觸發(fā)sticky時(shí)展示shadow</p>
  </section>

  <script>
    const header = document.getElementById('sticky-header');
    const section = document.querySelector('section');

    const options = {
      threshold: 1
    };
    //guard滾動(dòng)到可視區(qū)域以外時(shí)認(rèn)為觸發(fā)了shadow
    const intersectionObserver = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          header.classList.remove('shadow');
        } else {
          header.classList.add('shadow');
        }
      });
    }, options);

    intersectionObserver.observe(document.getElementById('guard'));
  </script>

</body>
</html>

3.3.2、預(yù)覽

在線源碼請(qǐng)點(diǎn)擊【前往

3.3.3、效果

四、ResizeObserver

ResizeObserver是用于監(jiān)聽(tīng)DOM尺寸變化的observer,當(dāng)DOM尺寸變化是執(zhí)行callback

4.1、基本使用

和前面的api用法差不多,這里不過(guò)多介紹。

const box = document.getElementById('box');

const resizeObserver = new ResizeObserver(entries => {
  entries.forEach(entry => {
    console.log(entry)
  });
});

resizeObserver.observe(box);

4.2、API介紹

entry對(duì)象包含resize相關(guān)的信息,下面看一下entry的結(jié)構(gòu)

{
  // 不同box-sizing下的尺寸
  borderBoxSize: [{
    blockSize: 200,
    inlineSize: 200,
  }],
  contentBoxSize: [{
    blockSize: 200,
    inlineSize: 200,
  }],
  contentRect: {
    bottom: 200,
    height: 200,
    left: 0,
    right: 200,
    top: 0,
    width: 200,
    x: 0,
    y: 0
  },
  // 在物理設(shè)備像素上的大小, 在不同的屏幕上尺寸不同例如Retina
  devicePixelContentBoxSize: [{
      blockSize: 300,
      inlineSize: 300
    }
  ],
  target: div#resizable-box
}

4.3、常見(jiàn)場(chǎng)景

可以基于ResizeObserver實(shí)現(xiàn)一個(gè)簡(jiǎn)單的resize-detector(參考react-resize-detector),在尺寸變化時(shí)返回尺寸信息,點(diǎn)擊盒子就算拖拽有效。

4.3.1、源碼

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ResizeObserver Demo with Resizable Box</title>
  <style>
    #resizable-box {
      width: 200px;
      height: 200px;
      background-color: #3498db;
      color: white;
      text-align: center;
      line-height: 200px;
      font-size: 24px;
      transition: background-color 0.5s ease;
      resize: both;
      overflow: auto;
      cursor: pointer;
    }
  </style>
</head>
<body>

  <div id="resizable-box">Resize me!</div>

  <script>
    const resizableBox = document.getElementById('resizable-box');
    let isResizing = false;
    let startX, startY, startWidth, startHeight;

    const resizeObserver = new ResizeObserver(entries => {
      for (const entry of entries) {
        const { width, height } = entry.contentRect;
        console.log('寬度:', width, '高度:', height);
      }
    });

    resizeObserver.observe(resizableBox);

    resizableBox.addEventListener('mousedown', startResize);
    document.addEventListener('mousemove', handleResize);
    document.addEventListener('mouseup', stopResize);

    function startResize(e) {
      isResizing = true;
      startX = e.clientX;
      startY = e.clientY;
      startWidth = parseInt(document.defaultView.getComputedStyle(resizableBox).width, 10);
      startHeight = parseInt(document.defaultView.getComputedStyle(resizableBox).height, 10);
    }

    function handleResize(e) {
      if (!isResizing) return;
      const newWidth = startWidth + (e.clientX - startX);
      const newHeight = startHeight + (e.clientY - startY);

      resizableBox.style.width = newWidth + 'px';
      resizableBox.style.height = newHeight + 'px';
    }

    function stopResize() {
      isResizing = false;
    }
  </script>

</body>
</html>

4.3.2、預(yù)覽

在線源碼請(qǐng)點(diǎn)擊【前往

4.3.3、效果

五、PerformanceObserver

PerformanceObserver用于監(jiān)聽(tīng)瀏覽器的performance事件,方便在performance事件觸發(fā)時(shí)作統(tǒng)一處理。

5.1、基本使用

// mdn demo
function perf_observer(list, observer) {
  console.log(list)
}
var observer2 = new PerformanceObserver(perf_observer);
// entryTypes用于指定要監(jiān)聽(tīng)的事件類(lèi)型
observer2.observe({ entryTypes: ["measure"] });

5.2、API介紹

下面列一下常見(jiàn)的entryTypes

  • mark:用于標(biāo)記時(shí)間戳的事件
  • measureperformance.measure觸發(fā)的事件
  • frame:網(wǎng)頁(yè)渲染的事件
  • navigation:導(dǎo)航的事件,例如頁(yè)面加載或重新加載
  • resource:資源加載事件
  • longtask:長(zhǎng)任務(wù)事件
  • paint:繪制事件,例如FP,FCP
  • layout-shift:用于監(jiān)視布局變化的事件

對(duì)于對(duì)性能比較敏感的項(xiàng)目以及長(zhǎng)期性能監(jiān)控來(lái)說(shuō)這個(gè)api還是比較方便的。

六、ReportingObserver

ReportingObserver用于監(jiān)聽(tīng)瀏覽器報(bào)告的事件,例如廢棄API,過(guò)時(shí)特性,網(wǎng)絡(luò)錯(cuò)誤。做監(jiān)控SDK的同學(xué)應(yīng)該經(jīng)常能用到,日常業(yè)務(wù)代碼用的比較少。

6.1、基本使用

這里就簡(jiǎn)單看一下使用方法吧,比較簡(jiǎn)單

const observer = new ReportingObserver((reports, observer) => {
  reports.forEach(report => {
    console.log(report);
  });
});

// 監(jiān)聽(tīng)過(guò)時(shí)特性
observer.observe({ types: ['deprecation'] });

七、最后

到此這篇關(guān)于JavaScript中5個(gè)重要的Observer函數(shù)小結(jié)的文章就介紹到這了,更多相關(guān)JavaScript Observer內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 禁止拷貝網(wǎng)頁(yè)內(nèi)容的js代碼

    禁止拷貝網(wǎng)頁(yè)內(nèi)容的js代碼

    如何禁止拷貝網(wǎng)頁(yè)內(nèi)容,想維護(hù)下自己的版權(quán),下面有個(gè)不錯(cuò)的方法,大家可以學(xué)習(xí)下
    2014-01-01
  • JavaScript實(shí)現(xiàn)九九乘法表的簡(jiǎn)單實(shí)例

    JavaScript實(shí)現(xiàn)九九乘法表的簡(jiǎn)單實(shí)例

    下面小編就為大家?guī)?lái)一篇JavaScript實(shí)現(xiàn)九九乘法表的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-06-06
  • JavaScript中常見(jiàn)獲取元素的方法匯總

    JavaScript中常見(jiàn)獲取元素的方法匯總

    本文向大家介紹了javascript中常見(jiàn)的3種獲取元素的方法,分別是通過(guò)元素ID、通過(guò)標(biāo)簽名字和通過(guò)類(lèi)名字來(lái)獲取,并附上了示例,希望大家能夠喜歡。
    2015-03-03
  • 觸屏中的JavaScript事件分析

    觸屏中的JavaScript事件分析

    這篇文章主要介紹了觸屏中的JavaScript事件,實(shí)例分析了觸屏事件的種類(lèi)、原理與相關(guān)使用技巧,需要的朋友可以參考下
    2015-02-02
  • 五段實(shí)用的js高級(jí)技巧

    五段實(shí)用的js高級(jí)技巧

    五段實(shí)用的js高級(jí)技巧,一些不錯(cuò)的小技巧,學(xué)習(xí)js的朋友可以看看。
    2011-12-12
  • javascript 事件加載與預(yù)加載

    javascript 事件加載與預(yù)加載

    本文對(duì)JavaScript事件加載進(jìn)行了一些延伸思考。加載多個(gè)事件時(shí),使用window.onload可能會(huì)導(dǎo)致一些不便,而通過(guò)偵聽(tīng)器等方法,則可以解決這些問(wèn)題。
    2009-12-12
  • ES6 Promise對(duì)象概念與用法分析

    ES6 Promise對(duì)象概念與用法分析

    這篇文章主要介紹了ES6 Promise對(duì)象概念與用法,簡(jiǎn)單分析了Promise對(duì)象的基本狀態(tài)與三種重要方法,并結(jié)合實(shí)例形式給出相關(guān)使用技巧,需要的朋友可以參考下
    2017-04-04
  • JS原型與原型鏈的深入理解

    JS原型與原型鏈的深入理解

    這篇文章主要和大家一起深入理解JS原型與原型鏈,原型是JavaScript中一個(gè)比較難理解的概念,本文為大家解決這個(gè)難題,感興趣的小伙伴們可以參考一下
    2017-02-02
  • JavaScript async/await原理及實(shí)例解析

    JavaScript async/await原理及實(shí)例解析

    這篇文章主要介紹了JavaScript async/await原理及實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12
  • 實(shí)例解析ES6 Proxy使用場(chǎng)景介紹

    實(shí)例解析ES6 Proxy使用場(chǎng)景介紹

    本篇文章主要介紹了ES6 Proxy使用場(chǎng)景介紹,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01

最新評(píng)論