mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-01 23:38:37 +00:00
fix: gallery render (#6742)
* fix: gallery render * fix: gallery render --------- Co-authored-by: 杨国璇 <ygx@Hello-word.local>
This commit is contained in:
parent
9e78a7aa93
commit
acbd02d071
@ -10,18 +10,14 @@ import toaster from '../../../../../components/toast';
|
||||
|
||||
import './index.css';
|
||||
|
||||
const CONCURRENCY_LIMIT = 3;
|
||||
const IMAGE_GAP = 2;
|
||||
|
||||
const Gallery = () => {
|
||||
const imageRefs = useRef([]);
|
||||
const containerRef = useRef(null);
|
||||
const [isFirstLoading, setFirstLoading] = useState(true);
|
||||
const [isLoadingMore, setLoadingMore] = useState(false);
|
||||
const [zoomGear, setZoomGear] = useState(0);
|
||||
const [containerWidth, setContainerWidth] = useState(0);
|
||||
const [loadingQueue, setLoadingQueue] = useState([]);
|
||||
const [concurrentLoads, setConcurrentLoads] = useState(0);
|
||||
const [overScan, setOverScan] = useState({ top: 0, bottom: 0 });
|
||||
const renderMoreTimer = useRef(null);
|
||||
|
||||
@ -66,22 +62,27 @@ const Gallery = () => {
|
||||
}, []);
|
||||
|
||||
let _groups = [];
|
||||
const imageHeight = imageSize + IMAGE_GAP;
|
||||
init.forEach((_init, index) => {
|
||||
const { children } = _init;
|
||||
const childrenCount = children.length;
|
||||
const value = childrenCount / columns;
|
||||
const rows = childrenCount % columns ? Math.ceil(value) : ~~(value);
|
||||
const height = rows * (imageSize + IMAGE_GAP);
|
||||
const { children, ...__init } = _init;
|
||||
let top = 0;
|
||||
let rows = [];
|
||||
if (index > 0) {
|
||||
const lastGroup = _groups[index - 1];
|
||||
const { top: lastGroupTop, height: lastGroupHeight } = lastGroup;
|
||||
top = lastGroupTop + lastGroupHeight;
|
||||
}
|
||||
children.forEach((child, childIndex) => {
|
||||
const rowIndex = ~~(childIndex / columns);
|
||||
if (!rows[rowIndex]) rows[rowIndex] = { top: top + rowIndex * imageHeight, children: [] };
|
||||
rows[rowIndex].children.push(child);
|
||||
});
|
||||
const height = rows.length * imageHeight;
|
||||
_groups.push({
|
||||
..._init,
|
||||
...__init,
|
||||
top,
|
||||
height,
|
||||
children: rows
|
||||
});
|
||||
});
|
||||
return _groups;
|
||||
@ -105,35 +106,6 @@ const Gallery = () => {
|
||||
|
||||
}, [isLoadingMore, metadata, store]);
|
||||
|
||||
const loadNextImage = useCallback(() => {
|
||||
if (loadingQueue.length === 0 || concurrentLoads >= CONCURRENCY_LIMIT) return;
|
||||
|
||||
const nextImage = loadingQueue.shift();
|
||||
setConcurrentLoads(prev => prev + 1);
|
||||
|
||||
const img = new Image();
|
||||
imageRefs.current.push(img);
|
||||
img.src = nextImage.src;
|
||||
img.onload = () => {
|
||||
setConcurrentLoads(prev => {
|
||||
const newCount = prev - 1;
|
||||
return newCount;
|
||||
});
|
||||
loadNextImage();
|
||||
};
|
||||
img.onerror = () => {
|
||||
setConcurrentLoads(prev => {
|
||||
const newCount = prev - 1;
|
||||
return newCount;
|
||||
});
|
||||
loadNextImage();
|
||||
};
|
||||
}, [loadingQueue, concurrentLoads]);
|
||||
|
||||
useEffect(() => {
|
||||
loadNextImage();
|
||||
}, [loadingQueue, concurrentLoads, loadNextImage]);
|
||||
|
||||
useEffect(() => {
|
||||
const gear = window.sfMetadataContext.localStorage.getItem('zoom-gear', 0) || 0;
|
||||
setZoomGear(gear);
|
||||
@ -152,8 +124,8 @@ const Gallery = () => {
|
||||
|
||||
// resize
|
||||
const handleResize = () => {
|
||||
if (!containerRef.current) return;
|
||||
setContainerWidth(containerRef.current.offsetWidth);
|
||||
if (!container) return;
|
||||
setContainerWidth(container.offsetWidth);
|
||||
};
|
||||
const resizeObserver = new ResizeObserver(handleResize);
|
||||
container && resizeObserver.observe(container);
|
||||
@ -162,17 +134,13 @@ const Gallery = () => {
|
||||
const modifyGalleryZoomGearSubscribe = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.MODIFY_GALLERY_ZOOM_GEAR, (zoomGear) => {
|
||||
window.sfMetadataContext.localStorage.setItem('zoom-gear', zoomGear);
|
||||
setZoomGear(zoomGear);
|
||||
setTimeout(() => {
|
||||
container.scrollTop += zoomGear * 10;
|
||||
}, 200);
|
||||
});
|
||||
return () => {
|
||||
container && resizeObserver.unobserve(container);
|
||||
modifyGalleryZoomGearSubscribe();
|
||||
|
||||
// Cleanup image references on unmount
|
||||
imageRefs.current.forEach(img => {
|
||||
img.onload = null;
|
||||
img.onerror = null;
|
||||
});
|
||||
imageRefs.current = [];
|
||||
renderMoreTimer.current && clearTimeout(renderMoreTimer.current);
|
||||
};
|
||||
}, []);
|
||||
@ -194,17 +162,12 @@ const Gallery = () => {
|
||||
}
|
||||
}, [imageSize, loadMore, renderMoreTimer]);
|
||||
|
||||
const addToQueue = (image) => {
|
||||
setLoadingQueue(prev => [...prev, image]);
|
||||
loadNextImage();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="sf-metadata-container">
|
||||
<div className="sf-metadata-gallery-container" ref={containerRef} onScroll={handleScroll} >
|
||||
{!isFirstLoading && (
|
||||
<>
|
||||
<Main groups={groups} size={imageSize} onLoad={addToQueue} columns={columns} overScan={overScan} gap={IMAGE_GAP} />
|
||||
<Main groups={groups} size={imageSize} columns={columns} overScan={overScan} gap={IMAGE_GAP} />
|
||||
{isLoadingMore && (<div className="sf-metadata-gallery-loading-more"><CenteredLoading /></div>)}
|
||||
</>
|
||||
)}
|
||||
|
@ -1,25 +1,25 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Main = ({ groups, overScan, columns, onLoad, size, gap }) => {
|
||||
const Main = ({ groups, overScan, columns, size, gap }) => {
|
||||
const imageHeight = useMemo(() => size + gap, [size, gap]);
|
||||
|
||||
const renderDisplayGroup = useCallback((group) => {
|
||||
const { top: overScanTop, bottom: overScanBottom } = overScan;
|
||||
const { name, children, top, height } = group;
|
||||
let childrenStartIndex = children.findIndex((r, i) => {
|
||||
const rTop = ~~(i / columns) * (size + 2) + top;
|
||||
return rTop >= overScanTop;
|
||||
});
|
||||
childrenStartIndex = Math.max(childrenStartIndex, 0);
|
||||
let childrenEndIndex = children.findIndex((r, i) => {
|
||||
const rTop = ~~(i / columns) * (size + gap) + top;
|
||||
return rTop >= overScanBottom;
|
||||
});
|
||||
if (childrenEndIndex > -1 && childrenEndIndex !== 0) {
|
||||
childrenEndIndex = childrenEndIndex - 1;
|
||||
const { name, children, height, top } = group;
|
||||
|
||||
// group not in render area, return empty div
|
||||
if (top >= overScanBottom || top + height <= overScanTop) {
|
||||
return (<div key={name} className="w-100" style={{ height, flexShrink: 0 }}></div>);
|
||||
}
|
||||
|
||||
const childrenStartIndex = children.findIndex(r => r.top >= overScanTop);
|
||||
let childrenEndIndex = children.findIndex(r => r.top >= overScanBottom);
|
||||
if (childrenEndIndex === -1) {
|
||||
childrenEndIndex = children.length - 1;
|
||||
childrenEndIndex = children.length;
|
||||
}
|
||||
if (childrenEndIndex > 0) {
|
||||
childrenEndIndex = childrenEndIndex - 1;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -29,24 +29,23 @@ const Main = ({ groups, overScan, columns, onLoad, size, gap }) => {
|
||||
className="metadata-gallery-image-list"
|
||||
style={{
|
||||
gridTemplateColumns: `repeat(${columns}, 1fr)`,
|
||||
paddingTop: ~~(childrenStartIndex / columns) * (size + gap),
|
||||
paddingBottom: ~~((children.length - 1 - childrenEndIndex) / columns) * (size + gap),
|
||||
paddingTop: childrenStartIndex * imageHeight,
|
||||
paddingBottom: (children.length - 1 - childrenEndIndex) * imageHeight,
|
||||
}}
|
||||
>
|
||||
{children.slice(childrenStartIndex, childrenEndIndex).map((img) => (
|
||||
<div key={img.src} tabIndex={1} className='metadata-gallery-image-item' style={{ width: size, height: size }}>
|
||||
<img
|
||||
className="metadata-gallery-grid-image"
|
||||
src={img.src}
|
||||
alt={img.name}
|
||||
onLoad={() => onLoad(img)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{children.slice(childrenStartIndex, childrenEndIndex + 1).map((row) => {
|
||||
return row.children.map(img => {
|
||||
return (
|
||||
<div key={img.src} tabIndex={1} className="metadata-gallery-image-item" style={{ width: size, height: size, background: '#f1f1f1' }}>
|
||||
<img className="metadata-gallery-grid-image" src={img.src} alt={img.name} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}, [overScan, columns, onLoad, size, gap]);
|
||||
}, [overScan, columns, size, imageHeight]);
|
||||
|
||||
if (!Array.isArray(groups) || groups.length === 0) return null;
|
||||
return groups.map((group, index) => {
|
||||
@ -58,7 +57,6 @@ Main.propTypes = {
|
||||
groups: PropTypes.array,
|
||||
overScan: PropTypes.object,
|
||||
columns: PropTypes.number,
|
||||
onLoad: PropTypes.func,
|
||||
size: PropTypes.number,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user