• React Hooks 实现图片懒加载useLazyLoad


    定义useLazyLoad

    思路: 判断图片在视口内就加载,即: 元素距离页面顶部的距离offsetTop < 滚动条高度scrollTop + 视口高clientHeight

    import { useCallback, useEffect, useState } from 'react'
    import { ImgDOMListType, ImageListType } from '../components/LazyLoadDemo'
    import useThrottle from './useDebounce'
    
    interface LazyLoadPropsType {
        domList: ImgDOMListType,
        imgList: ImageListType,
        throttle: number
    }
    
    const useLazyLoad = ({ domList, imgList, throttle }: LazyLoadPropsType) => {
    
        const [scrollCount, setScrollCount] = useState(0)
    
        // 节流
        const loadImg = useThrottle(() => {
            domList.forEach((el, i) => {
                // 已经加载的无需继续加载
                if (!el || imgList[i].loaded) return
                // 加载条件:判断元素在视口内,即图片距离页面顶部的距离 offsetTop < 滚动条高度+视口高
                if (el.offsetTop < document.documentElement.scrollTop + document.documentElement.clientHeight) {
                    el.src = el.dataset.src as string
                    imgList[i].loaded = true
                }
            })
        }, throttle, [domList, imgList, throttle])
    
        const beginLoad = useCallback(() => setScrollCount(v => v + 1), [setScrollCount])
    
        // 监听scroll事件
        useEffect(() => {
            document.addEventListener('scroll', beginLoad)
            return () => document.removeEventListener('scroll', beginLoad)
        }, [beginLoad])
    
        // 开始计算懒加载图片位置
        useEffect(() => {
            loadImg()
        }, [loadImg, scrollCount])
    
    }
    
    export default useLazyLoad
    

    测试用例

    import { useRef } from "react"
    import useLazyLoad from "../hooks/useLazyLoad"
    
    import './LazyLoadDemo.css'
    
    export type ImageListType = Array<{
        id: number | string,
        src: string,
        loadingSrc: string,
        loaded: boolean
    }>
    export type ImgDOMListType = Array<HTMLImageElement | null>
    
    const loadingSrc = 'https://www.maojiemao.com/public/svg/gen1.png'
    const src = 'https://www.maojiemao.com/public/svg/gen2.png'
    
    const imgList: ImageListType = Array.from({ length: 30 }).map((v, i) => ({
        id: i,
        src,
        loadingSrc,
        loaded: false
    }))
    
    const LazyLoadDemo: React.FC = () => {
        const domRef = useRef<ImgDOMListType>([])
        useLazyLoad({ domList: domRef.current, imgList, throttle: 200 })
    
        return (
            <div className="wrapper">
                {
                    imgList.map((v, i: number) =>
                        <img
                            key={i}
                            ref={(el) => (domRef.current[i] = el)}
                            src={v.loadingSrc}
                            data-src={v.src}
                            alt=""
                            className="item" />
                    )
                }
            </div>
        )
    }
    
    export default LazyLoadDemo
    
  • 相关阅读:
    C#3.0分部份方法
    欢迎提议
    控制台关闭的特殊处理
    好头晕
    c#如何计算当月季度时间段
    CMMI定义(转)
    SQL Server 聚集索引和非聚集索引的区别
    ObjectBuilder2.0 的学习
    WaitHandle、AutoResetEvent、ManualResetEvent整理
    使用XML RPC进行远程调用
  • 原文地址:https://www.cnblogs.com/ltfxy/p/16395302.html
Copyright © 2020-2023  润新知