在react當中利用IntersectionObserve實現下拉加載數據

目錄

一、傳統的下拉加載方案

二、存在問題

1.性能較差

2.不夠精確

三、IntersectionObserve版本下拉加載

1、callback

2、options

四、IntersectionObserver實例

1、Intersection的優勢

2、實現思路

3、代碼實現


在進行前端開發的過程中,常常會碰到下拉加載列表數據的需求。本文將介紹如何利用Intersection API實現一個簡單的下拉加載數據的demo。

一、傳統的下拉加載方案

傳統的下拉加載方案大多數都是通過監聽scroll事件,然后獲取目標元素坐標以及相關數據,再進行對應的實現。例如下面就是一個依賴數據列表容器的scrollHeightscrollTopheight實現的下拉加載的demo。

function App() {// 用于記錄當前是否正在請求中const loadingRef = useRef<boolean>(false);// 列表容器const containerRef = useRef<HTMLDivElement>(null);const [dataList, setDataList] = useState([]);useEffect(() => {fetchData();}, []);useEffect(() => {const { height } = containerRef.current.getBoundingClientRect();const scrollHeight = containerRef.current.scrollHeight;const onScroll = () => {console.log('scrollHeight:', scrollHeight, 'scrollTop:', containerRef.current.scrollTop, 'height:', height);if (scrollHeight - containerRef.current.scrollTop - 1 <= height) {// 當容器已經拉到最底部時,發起請求fetchData();}};containerRef.current.addEventListener('scroll', onScroll);return () => {containerRef.current.removeEventListener('scroll', onScroll);};}, []);const fetchData = () => {// 模擬數據請求// 如果當前正在請求中,直接返回if (loadingRef.current) return;// 標記當前正在請求中loadingRef.current = true;setTimeout(() => {setDataList(_dataList => {const dataList = [..._dataList];for (let i = 0; i < 20; i++) {dataList.push(Math.random());}return dataList;});loadingRef.current = false;}, 500);};return (<div ref={containerRef} className="list-container">{dataList.map(item => (<p className="list-item" key={item}>{item}</p>))}<div className="loading">loading...</div></div>);
}

二、存在問題

1.性能較差

我們知道,scroll事件的發生是十分密集的,在監聽scroll事件的回調函數中,我們都要重新獲取列表容器的scrollTop,這會導致“重排”的發生。此時需要我們額外去做一些防抖或是節流的工具,防止造成性能問題。

// 節流
throttle(onScroll, 500);

2.不夠精確

scrollTop的小數問題 眼尖的同學可能已經看到的,我們在判斷容器是否已經滾動到底部是,還做了一個-1的操作。

if (scrollHeight - containerRef.current.scrollTop - 1 <= height) {// 當容器已經拉到最底部時,發起請求fetchData();
}

這是因為在使用顯示比例縮放的系統上,scrollTop可能會提供一個小數。如下圖所示,在容器滾動到底部時,scrollHeight(1542) - scrollTop(1141.5999755859375)?與容器的高度height(400)并不相等。

所以我們需要做出相應的兼容處理。

三、IntersectionObserve版本下拉加載

IntersectionObserver 提供了一種異步觀察目標元素在其祖先元素或頂級文檔視窗(viewport)中是否可視的方法。

IntersectionObserver的用法十分簡單,我們只需要定義好DOM元素的可視狀態發生變化后需要做些什么,以及需要觀察哪些元素的可視狀態就好了。

接下來我們詳細的看看intersectionObserver這個API。

const intersectionObserver = new IntersectionObserver(callback, options?) ;

?IntersectionObserver構造函數會接收兩個參數。

1、callback

callback為被觀察元素的可視狀態發生變更后的回調函數,此回調函數接受兩個參數:

function callback(entries, observer?) => {//...
}

entries:一個IntersectionObserverEntry對象的數組。IntersectionObserverEntry對象用于描述被觀察對象的可視狀態的變化,擁有以下的屬性:

  • entry.boundingClientRect:被觀察元素的邊界信息,相當于被觀察元素調用getBoundingClientRect()的結果。
  • entry.intersectionRatio:被觀察元素與容器元素相交矩形面積與被觀察元素總面積的比例。
  • entry.intersectionRect:相交矩形的邊界信息。
  • entry.isIntersecting:一個布爾值,表示被觀察元素是否可視,如果是true,則表示元可視,反之則表示不可視。
  • entry.rootBounds:容器元素的邊界信息,相當于容器元素調用getBoundingClientRect()的結果。
  • entry.target:被觀察的元素的引用。
  • entry.time:當前時間戳。

observer:當前IntersectionObserver實例的引用。

2、options

options為一個可選參數,可傳入以下屬性:

  • root:指定容器元素,默認為瀏覽器窗體元素。容器元素必須是目標元素的祖先節點。
  • rootMargin:用于擴展或縮小rootBounds的大小,用法與CSS中margin一致,默認值為默認值是"0px 0px 0px 0px"。
  • threshold:number或number數組,用于指定callback回調函數執行的閾值,如傳入[0, 0.2, 0.6, 0.8, 1]時,intersectionRatio每增加或減少0.2時都會觸發回調函數的執行。默認值為0。需要注意的時,由于回調函數時異步觸發的,在回調函數執行時intersectionRatio可能已經和指定的閾值不一致了。

四、IntersectionObserver實例

IntersectionObserver構造函數會把options中的屬性掛載到IntersectionObserver實例上,并賦予IntersectionObserver實例四個方法:

  • IntersectionObserver.disconnect():停止監聽工作。
  • IntersectionObserver.observe(targetElem):開始監聽某個元素可視狀態的變化。
  • IntersectionObserver.takeRecords():返回所有觀察目標的IntersectionObserverEntry對象數組。
  • IntersectionObserver.unobserve(targetElem):停止監聽某個目標元素。

1、Intersection的優勢

intersectionObserver構造函數中傳入的回調函數只會在觀察的元素的可視狀態發生變化后才會執行,很好的解決傳統判斷可視的方案的性能瓶頸。

2、實現思路

我們在實現下拉加載功能時,當數據列表還沒有加載完時,我們往往會在數據列表的最后放置一個loading組件,表示當數據列表還有更加數據,并且正在加載中。我們可以利用這個loading組件的可視狀態以及Intersection API實現Intersection版本的下拉加載。

3、代碼實現

實現一個DemoList.tsx

import { useEffect, useRef, useState } from 'react';const DemoList = () => {// 用于記錄當前是否正在請求中const loadingRef = useRef<boolean>(false);// loading divconst loadingDivRef = useRef<HTMLDivElement | null>(null);const observerRef = useRef<IntersectionObserver | null>(null);const [dataList, setDataList] = useState<number[]>([]);const fetchData = () => {// 模擬數據請求// 如果當前正在請求中,直接返回if (loadingRef.current) return;// 標記當前正在請求中loadingRef.current = true;setTimeout(() => {setDataList((_dataList) => {const dataList = [..._dataList];for (let i = 0; i < 100; i++) {// 這里面要注意的是把最新的請求的數據合并的時候要放在最后面,也就是說從數據的最后面添加。否則,就會出現連續請求的狀況。原因在于如果把最新的請求對的數據放最前面的話,新增的元素是從上面渲染,就會導致下面的加載元素一直處于可見的狀態,從而導致連續觸發的狀況dataList.push(Math.random());}return dataList;});loadingRef.current = false;}, 500);};useEffect(() => {fetchData();}, []);useEffect(() => {const target = loadingDivRef.current;if (!target) return;observerRef.current = new IntersectionObserver(function (entries) {if (entries[0].intersectionRatio > 0) {// intersectionRatio大于0,代表監聽的元素由不可見變成可見,進行數據請求fetchData();}});// 監聽Loading div的可見性if (loadingDivRef.current) observerRef.current.observe(loadingDivRef.current);return () => {if (observerRef.current) {if (target) observerRef.current.unobserve(target);observerRef.current.disconnect();observerRef.current = null;}};}, []);return (<div className="list-container">{dataList.map((item, index) => (<p className="list-item" key={item}>{index}——{item}</p>))}<div ref={loadingDivRef} className="loading">loading...</div></div>);
};export default DemoList;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/73629.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/73629.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/73629.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深入理解C++編程:從內存管理到多態與算法實現

C 是一門功能強大的編程語言&#xff0c;廣泛應用于系統編程、游戲開發和高性能計算等領域。本文將通過一系列經典問題&#xff0c;深入探討 C 的核心知識點&#xff0c;包括內存管理、多態&#xff08;結合函數重載與覆蓋&#xff09;、多線程、TCP/IP 模型、軟鏈接與硬鏈接的…

相對論之光速

然而&#xff0c;基礎物理學的進步很少全部由實驗取得。為了解實驗結果背后的機制&#xff0c;法拉第問道&#xff0c;既然磁鐵沒有接觸導線&#xff0c;導線中怎么會產生電流?一股電流又怎么能使指南針指針發生偏轉?有某種作用因素必然在磁鐵、導線和指南針之間的空隙中傳遞…

文本檢測-文本內容審核-文本過濾接口如何用PHP調用?

一、什么是文本檢測接口呢&#xff1f; 文本內容審核過濾&#xff0c;提供對敏感事件、違規詞語及監管要求封禁詞語的識別審核能力&#xff0c;包含海量歷史數據&#xff0c;有效過濾違禁違規、惡意推廣、低俗辱罵、低質灌水、廣告法審核&#xff0c;該接口應用場景廣泛&#…

突破極限:獵板PCB在HDI盲埋孔樹脂塞孔工藝中的創新與挑戰

在高端電子制造領域&#xff0c;HDI&#xff08;高密度互連&#xff09;技術憑借其高精度、高可靠性的特點&#xff0c;已成為5G通信、航空航天、智能汽車等領域的核心技術支撐。作為HDI板制造的核心環節&#xff0c;盲埋孔樹脂塞孔工藝直接決定了電路板的信號完整性、散熱性能…

群體智能優化算法-?魚優化算法 (Remora Optimization Algorithm, ROA,含Matlab源代碼)

摘要 ?魚優化算法&#xff08;Remora Optimization Algorithm&#xff0c;ROA&#xff09;是一種基于?魚在海洋中寄生與捕食者間交互關系而提出的元啟發式算法。通過模擬?魚在宿主附近進行寄生、吸附和隨機機動等行為&#xff0c;ROA 在全局與局部搜索之間取得平衡。本文提…

【數學建模】一致矩陣的應用及其在層次分析法(AHP)中的性質

一致矩陣在層次分析法(AHP)中的應用與性質 在層次分析法(AHP)中&#xff0c;一致矩陣是判斷矩陣的一種理想狀態&#xff0c;它反映了決策者判斷的完全合理性和一致性&#xff0c;也就是為了避免決策者認為“A比B重要&#xff0c;B比C重要&#xff0c;但是C又比A重要”的矛盾。…

DeepSeek R1 與 ktransformers:結合蘋果 M4 Mac 的 LLM 推理深度分析

引言 大型語言模型&#xff08;LLM&#xff09;的快速發展為人工智能領域帶來了革命性變化。DeepSeek R1 和 ktransformers 代表了軟件層面的最新突破&#xff0c;而蘋果在 2025 年 3 月 12 日發布的 M4 Mac 系列則提供了硬件支持。本文將深入分析這些技術的交匯點&#xff0c…

JavaScript基本知識

文章目錄 一、JavaScript基礎1.變量&#xff08;重點&#xff09;1-1 定義變量及賦值1-2 變量的命名規則和命名規范判斷數據類型&#xff1a; 2.數據類型轉換2-1 其他數據類型轉成數值2-2 其他數據類型轉成字符串2-3 其他數據類型轉成布爾 3.函數3-1函數定義階段3-2函數調用階段…

[IP]UART

UART 是一個簡易串口ip&#xff0c;用戶及配置接口簡單。 波特率從9600至2000000。 該 IP 支持以下特性&#xff1a; 異步串行通信&#xff1a;標準 UART 協議&#xff08;1 起始位&#xff0c;8 數據位&#xff0c;1 停止位&#xff0c;無奇偶校驗&#xff09;。 參數化配置…

K8s集群的環境部署

1.測試環境所需要的主機名和IP和扮演的角色 harbor 172.25.254.200 harbor倉庫 k8s-master 172.25.254.100 k8s集群控制節點 k8s-node1 172.25.254.10 k8s集群工作節點 k8s-node2 172.25.254.20 k8集群工作節點 注意&#xff1a;所有節點禁用selinux和防火墻 所有節點同步…

pytest自動化測試[面試篇]

pytest是python的測試框架&#xff0c;它提供了許多功能&#xff0c; 測試運行 組織pytest的測試用例代碼&#xff1a;模塊名稱以test_開頭&#xff0c;類名以Test開頭&#xff0c;函數名以test_開頭, 然后用pytest命令即可運行測試用例。 可以在命令行中&#xff0c;用pyte…

樹莓派急速安裝ubuntu;映射磁盤與儲存磁盤文件;ubuntu映射整個工程;保存系統工作狀態

一、用途 在使用樹莓派上下載ubuntu時&#xff0c;需要一張sd卡&#xff0c;當你需要給這張卡做備份的時候&#xff0c;可以是使用磁盤映射軟件&#xff0c;從而達到備份的目的 同時有一些大佬發布了ubuntu的映射文件&#xff0c;可以直接使用該文件&#xff0c;然后還原他的整…

Python學習第十九天

Django-分頁 后端分頁 Django提供了Paginator類來實現后端分頁。Paginator類可以將一個查詢集&#xff08;QuerySet&#xff09;分成多個頁面&#xff0c;每個頁面包含指定數量的對象。 from django.shortcuts import render, redirect, get_object_or_404 from .models impo…

Windows下安裝Git客戶端

① 官網地址&#xff1a;https://git-scm.com/。 ② Git的優勢 大部分操作在本地完成&#xff0c;不需要聯網&#xff1b;完整性保證&#xff1b;盡可能添加數據而不是刪除或修改數據&#xff1b;分支操作非常快捷流暢&#xff1b;與Linux 命令全面兼容。 ③ Git的安裝 從官網…

刷題練習筆記

目錄 1、消失的數字 2、旋轉數組 3、原地移除元素 4、刪除排序數組中的重復項 1、消失的數字 oj&#xff1a;面試題 17.04. 消失的數字 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff08;參考評論區&#xff09;&#xff1a; 利用異或的特性&#xff0c;ret ret …

C或C++中實現數據結構課程中的鏈表、數組、樹和圖案例

1. 雙向鏈表&#xff08;Doubly Linked List&#xff09;-----支持雙向遍歷。 C實現 #include <iostream>struct Node {int data;Node* prev;Node* next; };class DoublyLinkedList { private:Node* head; public:DoublyLinkedList() : head(nullptr) {}// 在鏈表末尾插…

94.HarmonyOS NEXT動畫系統實現教程:深入理解FuncUtils

溫馨提示&#xff1a;本篇博客的詳細代碼已發布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下載運行哦&#xff01; HarmonyOS NEXT動畫系統實現教程&#xff1a;深入理解FuncUtils 文章目錄 HarmonyOS NEXT動畫系統實現教程&#xff1a;深入理解FuncUtils1. 動畫系…

AI日報 - 2025年3月17日

&#x1f31f; 今日概覽&#xff08;60秒速覽&#xff09; ▎&#x1f916; AGI突破 | GPT-o1在卡內基梅隆大學數學考試中獲滿分&#xff0c;展示AI數學能力新高度 成本僅5美分/題&#xff0c;推理速度不到1分鐘 ▎&#x1f4bc; 商業動向 | Figure推出BotQ機器人制造設施&…

Tauri + Vite + SvelteKit + TailwindCSS + DaisyUI 跨平臺開發詳細配置指南(Windows)

Tauri Vite SvelteKit TailwindCSS DaisyUI 跨平臺開發詳細配置指南&#xff08;Windows&#xff09; 本文為博主原創文章&#xff0c;遵循 CC 4.0 BY-SA 版權協議。轉載請注明出處及本聲明 原文鏈接&#xff1a;[你的文章鏈接] &#x1f6e0;? 環境準備 1. 安裝核心工具…

在 macOS 上優化 Vim 用于開發

簡介 這篇指南將帶你通過一系列步驟&#xff0c;如何在 macOS 上優化 Vim&#xff0c;使其具備 代碼補全、語法高亮、代碼格式化、代碼片段管理、目錄樹等功能。此外&#xff0c;我們還會解決在安裝過程中可能遇到的常見錯誤。 1. 安裝必備工具 在開始 Vim 配置之前&#xff…