Created
August 25, 2021 21:25
-
-
Save nanxiaobei/1604f99d3307a1d93399250a19242d95 to your computer and use it in GitHub Desktop.
Image gallery with lazy load and dynamic list features
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useEffect, useRef } from "react"; | |
const ImageGallery = (props) => { | |
const { | |
type = "lazy-load", | |
list = [], | |
width = 300, | |
height = 300, | |
size = 3, | |
emitHeight = 150, | |
} = props; | |
const wrapper = useRef(null); | |
useEffect(() => { | |
const addSrc = (index) => { | |
const img = wrapper.current.children[index]; | |
if (!img || img.getAttribute("src")) return; | |
img.setAttribute("src", list[index]); | |
img.style.visibility = ""; | |
}; | |
const delSrc = (index) => { | |
const img = wrapper.current.children[index]; | |
if (!img || !img.getAttribute("src")) return; | |
img.setAttribute("src", ""); | |
img.style.visibility = "hidden"; | |
}; | |
const emitRatio = | |
emitHeight < 0 || emitHeight > height ? 0.5 : emitHeight / height; | |
let hasMount = false; | |
const observer = new IntersectionObserver( | |
(entries) => { | |
if (!hasMount) { | |
hasMount = true; | |
let edgeList = []; | |
entries.forEach((entry) => { | |
const { intersectionRatio, intersectionRect, target } = entry; | |
if (intersectionRatio === 0) return; | |
if (type === "lazy-load") { | |
if (intersectionRatio === 1) observer.unobserve(target); | |
} | |
const index = +target.dataset.index; | |
addSrc(index); | |
edgeList.push({ intersectionRatio, intersectionRect, index }); | |
}); | |
if (edgeList.length > size) { | |
edgeList = edgeList.slice(0, size).concat(edgeList.slice(-size)); | |
} | |
edgeList.forEach(({ intersectionRatio, intersectionRect, index }) => { | |
if (intersectionRatio < emitRatio) return; | |
const yDiff = intersectionRect.y === 0 ? -size : size; | |
addSrc(index + yDiff); | |
}); | |
} else { | |
entries.forEach((entry) => { | |
const { intersectionRatio, intersectionRect, target } = entry; | |
if (type === "lazy-load") observer.unobserve(target); | |
const index = +target.dataset.index; | |
const yDiff = intersectionRect.y === 0 ? -size : size; | |
if (intersectionRatio < emitRatio) { | |
if (type === "dynamic-list") delSrc(index + yDiff); | |
} else { | |
addSrc(index + yDiff); | |
} | |
}); | |
} | |
}, | |
{ threshold: [emitRatio] } | |
); | |
for (let img of wrapper.current.children) { | |
observer.observe(img); | |
} | |
}, [emitHeight, height, list, size, type]); | |
return ( | |
<div | |
ref={wrapper} | |
className="image-gallery" | |
style={{ display: "grid", grid: `auto / repeat(${size}, ${width}px)` }} | |
> | |
{list.map((_, index) => ( | |
<img | |
key={index} | |
data-index={index} | |
style={{ width: `${width}px`, height: `${height}px` }} | |
alt="" | |
/> | |
))} | |
</div> | |
); | |
}; | |
export default ImageGallery; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment