React實現(xiàn)圖片懶加載的常見方式
前言
圖片懶加載是一種優(yōu)化網(wǎng)頁性能的技術(shù),它允許在用戶滾動到圖片位置之前延遲加載圖片。通過懶加載,可以在用戶需要查看圖片時才加載圖片,避免了不必要的圖片加載,從而提高了網(wǎng)頁的加載速度和用戶體驗。
方案一
實現(xiàn)思路
在說明思路之前,先了解幾個常見的視圖屬性。
- clientHeight:可視區(qū)域的高度,對應(yīng)的也就是下圖中的滾動區(qū)域。
- scrollTop:滾動條滾動的高度,它指的是內(nèi)容區(qū)的頂部到可視區(qū)域頂部的距離。
- offsetTop:元素到offsetParent頂部的距離。
- offsetParent:距離元素最近的一個具有定位的祖宗元素(relative,absolute,fixed),若祖宗都不符合條件,offsetParent為body。
圖解:
根據(jù)上面的圖解可知,當(dāng)圖片的滾動條滾動的高度加上可視區(qū)域的高度大于當(dāng)前的圖片的offsetTop,那么說明圖片正在進入可視區(qū)域。這個時候便可以加載當(dāng)前圖片。
第一步
模擬后臺返回的圖片url,遍歷產(chǎn)生一個url集合,用于后面的懶加載使用。
const imgUrls = (num = 10) => { const urls = []; for (let i = 0; i < num; i++) { const url = `https://robohash.org/${i}.png`; urls.push(url); } return urls; };
第二步
遍歷圖片url集合,渲染100張loading圖片,css部分省略。
<div className={styles['box-one']} ref={scrollRef}> {imgUrls(100).map((item) => { return <img data-src={item} key={item} src={loadingUrl} alt="" />; })} </div>
效果預(yù)覽
第三步
監(jiān)聽容器的滾動事件,當(dāng)容器滾動時計算容器的高度加上滾動條的高度大于當(dāng)前圖片的offsetTop時加載當(dāng)前的圖片。完整代碼如下:
import loadingUrl from '@/assets/imgs/loading.jpg'; import { useEffect, useRef } from 'react'; import styles from '../index.less'; // 圖片url const imgUrls = (num = 10) => { const urls = []; for (let i = 0; i < num; i++) { const url = `https://robohash.org/${i}.png`; urls.push(url); } return urls; }; const LazyLoading = () => { const scrollRef = useRef({} as any); // 滾動事件 const changeScroll = () => { const clientHeight = scrollRef?.current.clientHeight; //可視區(qū)域高度 const scrollTop = scrollRef?.current.scrollTop; //滾動條滾動高度 const childNodes = scrollRef?.current.childNodes; // 獲取所有圖片集合 for (let j = 0; j < childNodes.length; j++) { const element = childNodes[j]; if (scrollTop + clientHeight > element.offsetTop) { element.src = element.getAttribute('data-src'); // 替換當(dāng)前的src } } }; useEffect(() => { changeScroll(); // 第一次渲染的時候替換loading圖片 }, []); return ( <div className={styles['box-one']} ref={scrollRef} onScroll={changeScroll}> {imgUrls(100).map((item) => { return <img data-src={item} key={item} src={loadingUrl} alt="" />; })} </div> ); }; export default LazyLoading;
效果預(yù)覽
方案二
實現(xiàn)思路
方案二的實現(xiàn)思路利用瀏覽器提供的 IntersectionObserver
API實現(xiàn)。IntersectionObserver
API提供了一種方便的方式來監(jiān)視目標(biāo)元素和其祖先元素或視窗之間的交叉狀態(tài)變化。當(dāng)目標(biāo)元素進入或離開視口時,可以觸發(fā)回調(diào)函數(shù),進行相應(yīng)的操作。它的原理是通過注冊一個回調(diào)函數(shù)來觀察特定元素的交叉狀態(tài)變化,并在滿足條件時執(zhí)行相應(yīng)的操作。
使用 IntersectionObserver
API非常簡單,可以通過創(chuàng)建一個 IntersectionObserver
實例,并傳入回調(diào)函數(shù)和選項對象來實現(xiàn)。回調(diào)函數(shù)會在目標(biāo)元素的交叉狀態(tài)發(fā)生變化時被調(diào)用,并接收一個參數(shù),包含有關(guān)交叉狀態(tài)的信息。
實現(xiàn)完整代碼
import loadingUrl from '@/assets/imgs/loading.jpg'; import styles from '../index.less'; import React, { useRef, useEffect, useState } from 'react'; // 圖片url const imgUrls = (num = 10) => { const urls = []; for (let i = 0; i < num; i++) { const url = `https://robohash.org/${i}.png`; urls.push(url); } return urls; }; const LazyLoadImage = ({ src, alt }) => { const [imageSrc, setImageSrc] = useState(loadingUrl); const imgRef = useRef(null as any); useEffect(() => { let observer: IntersectionObserver; if (imgRef.current) { // 創(chuàng)建IntersectionObserver實例 observer = new IntersectionObserver( ([entry]) => { // 當(dāng)圖片進入可視區(qū)域時,設(shè)置圖片地址進行加載 if (entry.isIntersecting) { setImageSrc(src); observer.unobserve(imgRef.current); } }, { rootMargin: '0px 0px 200px 0px', // 可視區(qū)域的上邊距設(shè)置為200px }, ); observer.observe(imgRef.current); //開始觀察目標(biāo)元素 } return () => { if (observer && observer.unobserve) { observer.unobserve(imgRef.current); } }; }, [src]); return <img ref={imgRef} src={imageSrc} alt={alt} />; }; const LazyLoading = () => { return ( <div className={styles['box-two']}> {imgUrls(100).map((item) => { return <LazyLoadImage src={item} alt="lazy load image" />; })} </div> ); }; export default LazyLoading;
實現(xiàn)效果
注意事項
在初始化的時候,需要給imageSrc設(shè)置一個初始化的loading地址,如果沒有的話,初始化的時候會加載多張圖片。
方案三
實現(xiàn)思路
利用react的懶加載庫react-lazyload
,在使用之前需要先安裝 yarn add react-lazyload
,這里介紹幾個它的常見屬性:
- scrollContainer: 指定的滾動的區(qū)域,默認值是undefined,如果沒有指定默認是窗口的視圖作為滾動區(qū)域。
- offset: 元素距離視口頂部的距離,當(dāng)達到這個距離時,元素將被加載。
- scroll: 是否監(jiān)聽滾動
- height: 渲染元素的占位符的高度。
- overflow : 如果溢出容器,延遲加載組件
代碼實現(xiàn)
因為這里實現(xiàn)的圖片懶加載是局部懶加載,所以需要指定 scrollContainer
,scrollContainer
的值DOM對象。在實現(xiàn)的過程中,同時需要設(shè)置overflow為true,以及height的值。
import react, { useRef, useEffect } from 'react'; import LazyLoad from 'react-lazyload'; import styles from '../index.less'; // 圖片url const imgUrls = (num = 10) => { const urls = []; for (let i = 0; i < num; i++) { const url = `https://robohash.org/${i}.png`; urls.push(url); } return urls; }; const LazyLoading = () => { const scrollRef = useRef({} as any); return ( <div className={styles['box-three']} ref={scrollRef}> {imgUrls(100).map((item) => { return ( <LazyLoad height={200} overflow={true} offset={0} key={item} scroll={true} scrollContainer={scrollRef.current} // DOM > <img src={item} alt="" /> </LazyLoad> ); })} </div> ); }; export default LazyLoading;
實現(xiàn)效果
以上就是React實現(xiàn)圖片懶加載的常見方式的詳細內(nèi)容,更多關(guān)于React圖片懶加載的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
react-redux及redux狀態(tài)管理工具使用詳解
Redux是為javascript應(yīng)用程序提供一個狀態(tài)管理工具集中的管理react中多個組件的狀態(tài)redux是專門作狀態(tài)管理的js庫(不是react插件庫可以用在其他js框架中例如vue,但是基本用在react中),這篇文章主要介紹了react-redux及redux狀態(tài)管理工具使用詳解,需要的朋友可以參考下2023-01-01ReactNative頁面跳轉(zhuǎn)Navigator實現(xiàn)的示例代碼
本篇文章主要介紹了ReactNative頁面跳轉(zhuǎn)Navigator實現(xiàn)的示例代碼,具有一定的參考價值,有興趣的可以了解一下2017-08-08React使用Context與router實現(xiàn)權(quán)限路由詳細介紹
這篇文章主要介紹了React使用Context與router實現(xiàn)權(quán)限路由的詳細過程,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-01-01React工作流程及Error Boundaries實現(xiàn)過程講解
這篇文章主要介紹了React工作流程及Error Boundaries實現(xiàn)過程講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-02-02React Native中的RefreshContorl下拉刷新使用
本篇文章主要介紹了React Native中的RefreshContorl下拉刷新使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10