2025-10-27 02:24:02 世界杯小组积分

从零开始实现lazy

引言

在现代网页开发中,页面性能是至关重要的。当页面包含大量图片或其他媒体资源时,如果一次性全部加载,可能会导致页面加载缓慢,影响用户体验。懒加载技术通过只在用户需要时才加载资源,有效地解决了这个问题。

懒加载原理

懒加载的基本原理是利用浏览器的 IntersectionObserver API检测元素是否处于可见区域内。

当页面加载时,组件最初展示一个占位元素,组件的子元素暂不展示。当用户滚动页面时,通过 JavaScript 检测LazyLoad是否进入了可视区域,如果进入可视区域,则将控制展示子元素,从而触发加载。

组件入参设计

export type LazyLoadProps = {

/**

* 懒加载的元素

*/

children?: ReactNode

/**

* 懒加载的距离

*/

offset?: number | string

/**

* 懒加载的回调

*/

onLoad?: () => void

/**

* 占位元素

*/

placeholder?: ReactNode

className?: string

style?: React.CSSProperties

/**

* 传递查询选择器字符串或 DOM 节点。如果没有传递容器,LazyLoad 将附加到窗口对象的滚动事件。

*/

getContainer?: () => HTMLElement | null

}

组件实现

export function LazyLoad({

children,

offset = 0,

onLoad,

placeholder,

className,

style,

getContainer,

}: LazyLoadProps) {

const containerRef = useRef(null)

const [show, setShow] = useState(false)

useEffect(() => {

const observer = new IntersectionObserver(

(entries) => {

for (const entry of entries) {

if (entry.isIntersecting) {

setShow(true)

onLoad?.()

observer.unobserve(entry.target)

}

}

},

{

rootMargin: typeof offset === 'number' ? `${offset}px` : offset || '0px',

threshold: 0,

root: getContainer?.(),

},

)

if (containerRef.current) {

observer.observe(containerRef.current)

}

return () => {

observer.disconnect()

}

}, [onLoad, offset, getContainer])

return (

{show ? children : placeholder}

)

}

使用

import React from 'react'

import ReactDOM from 'react-dom'

import { LazyLoad } from './components/lazy-load'

import MyComponent from './MyComponen'

const App = () => {

return (

/* Lazy loading images is supported out of box, no extra config

needed, set `height` for better experience */

/* Once this component is loaded, LazyLoad will not care about it anymore, set this to

`true` if you're concerned about improving performance */

/* This component will be loaded when it's top edge is 100px from viewport. It's useful to

make user ignorant about lazy load effect. */

)

}

ReactDOM.render(, document.body)