Make a react-window (2)
react-window2
Introduce:
as last time introduce react-window , I had separate the design structure try to understand how it work , and today I’m going use IntersectionObserverEntry to ****make simliar as react-window List component
List design
Div design:
react-window paremeter is by px , here I want did some different is by hv , that will be more availability on the responsive
- div1: we need set max height value when child element is over size will show scroll barmax-height: <parameter>by hvoverflow: auto
- div2: here we need set virtual height for scroll barheight: itemCount * rowheight = total heightposition: relative
- row div: per row we need give the top height to align and positionposition: absolutetop: by current indexclassName: tr
IntersectionObserverEntry:
we need pass two paremeter to IntersectionObserver
- option :
const options = {root: document.getElementById('List'),rootMargin: `-${rowHeight}px 0px -${rowHeight}px 0px`,threshold: 0,};
- callbackFunction :
useEffect(() => {
let rowHeight = 0;
const elementArrary2 = Array.prototype.slice.call(document.getElementsByClassName('tr')) as HTMLDivElement[];
rowHeight = elementArrary2[0].clientHeight;
const options = {
root: document.getElementById('List'),
rootMargin: `-${rowHeight}px 0px -${rowHeight}px 0px`,
threshold: 0,
};
const onEnterView = (entries: IntersectionObserverEntry[], observer: IntersectionObserver) => {
for (let entry of entries) {
if (entry.isIntersecting) {
const element = entry.target as HTMLDivElement;
const value = parseInt(element.style.top.split('hv')[0]);
if (value > height && value > currentIndex.current * rowheight) {
const reangeValue = value - height;
currentIndex.current = reangeValue / rowheight;
setMaxValue(value2 + currentIndex.current);
} else if (0 !== currentIndex.current && value <= currentIndex.current * rowheight) {
currentIndex.current = value / rowheight;
currentIndex.current -= 1;
setMaxValue(value2 + currentIndex.current > height ? height : value2 + currentIndex.current);
}
}
}
};
const watcher = new IntersectionObserver(onEnterView, options);
const elementArrary = Array.prototype.slice.call(document.getElementsByClassName('tr'));
for (let image of elementArrary) {
watcher.observe(image);
}
}, [maxValue]);
Dom
return (
<div style={{ maxHeight: `${height}vh`, overflow: 'auto' }} id='List' className={classNames(` overflow-auto w-full relative`)}>
<div
className={`block `}
style={{
position: 'relative',
height: `${Rows?.length ? Rows?.length * rowheight : 2 * rowheight}vh`,
}}
>
{Rows?.slice(currentIndex.current, maxValue).map((item, index) => (
<div
key={shortid.generate()}
className={`tr absolute`}
style={{
top: `${(index + currentIndex.current) * rowheight}vh`,
position: 'absolute',
}}
>
<Children index={index + currentIndex.current}></Children>
</div>
))}
</div>
</div>
);
basically we are use Arrary slice function change currentIndex and maxValue when next element is be watched ,then will fall into the conditional and then them will be changed, and top height will be dynamic set up
Demo:
you can checkout more detail on this
https://codesandbox.io/s/nostalgic-sid-007ic8?from-embed
Github
you can checkout more detail on the github
conclusion:
the reason I will dig more about the vitrual scroll tech is flexibility and customize requirement , as I use IntersectionObserverEntry as along that make me more familar with it ,but currently my Algorithm I think is not a perfect solution it’s still had optimization space , but I will working on it
留言
張貼留言