最近在做即时消息,消息类型除了文字还有音频、视频、图片展示,如果消息很多,在切换聊天框时,会有明显卡顿,后续做了懒加载,方案是只加载用户能看到的资源,看不到的先不加载;
LazyAudio.tsx
import {useRef, useEffect} from 'react';
interface PropsType {
url: string,
className?: string,
}
export default function LazyAudio({url, className= ''}: PropsType) {
const currentRef: any = useRef(null)
useEffect(() => {
if (!currentRef.current) {
return;
}
const observer = new IntersectionObserver(([{ isIntersecting }]) => {
// 表示进入了可视范围
if (isIntersecting) {
if (!currentRef.current.src) {
currentRef.current.src = url;
observer.unobserve(currentRef.current);
}
}
});
observer.observe(currentRef.current);
return () => {
if (currentRef.current) {
observer.unobserve(currentRef.current);
}
}
}, [])
return (
<>
<audio
ref={currentRef}
controls
preload="metadata"
className={`${className} `}>
</audio>
</>
)
}
LazyImg.tsx
import {useEffect, useRef} from 'react';
interface PropsType {
url: string,
className?: string,
onClick: () => void,
}
export default function LazyImg({url, className = '', onClick}: PropsType) {
const currentRef: any = useRef(null)
// 图片加载完成后
const imageLoaded = () => {
// 图片加载完成后重置了高度
currentRef.current.style.height = 'auto';
}
useEffect(() => {
if (!currentRef.current) {
return;
}
const observer = new IntersectionObserver(([{ isIntersecting }]) => {
// 表示进入了可视范围
if (isIntersecting) {
if (!currentRef.current.src) {
currentRef.current.src = url;
observer.unobserve(currentRef.current);
}
}
});
observer.observe(currentRef.current);
return () => {
if (currentRef.current) {
observer.unobserve(currentRef.current);
}
}
}, [])
return <>
<img alt="无法加载图片"
width={320}
height={320}
ref={currentRef}
onClick={onClick}
onLoad={imageLoaded}
className={`${className} `}/>
</>
}
LazyVideo.tsx
import {useEffect, useRef} from 'react';
interface PropsType {
url: string,
className?: string,
width?: number,
height?: number,
}
export default function LazyVideo({url, className = '', width = 320, height = 240}: PropsType) {
const currentRef: any = useRef(null)
useEffect(() => {
if (!currentRef.current) {
return;
}
const observer = new IntersectionObserver(([{ isIntersecting }]) => {
// 表示进入了可视范围
if (isIntersecting) {
if (!currentRef.current.src) {
currentRef.current.src = url;
observer.unobserve(currentRef.current);
}
}
});
observer.observe(currentRef.current);
return () => {
if (currentRef.current) {
observer.unobserve(currentRef.current);
}
}
}, [])
return (
<>
<video
ref={currentRef}
width={width}
height={height}
controls
preload="metadata"
className={`${className} `}
>
</video>
</>
)
}