Skip to content

Instantly share code, notes, and snippets.

@nanxiaobei
Created August 25, 2021 21:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nanxiaobei/1604f99d3307a1d93399250a19242d95 to your computer and use it in GitHub Desktop.
Save nanxiaobei/1604f99d3307a1d93399250a19242d95 to your computer and use it in GitHub Desktop.
Image gallery with lazy load and dynamic list features
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