Make a react-window (2)
Previously:
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 bar
- max-height: <parameter>by hv
- overflow: auto - div2: here we need set virtual height for scroll bar
- height: itemCount * rowheight = total height
- position: relative - row div: per row we need give the top height to align and position
- position: absolute
- top: by current index
- className: 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 :
const Rows = Array.from(Array(itemCount).keys());const currentIndex = useRef(0);let value2 = height / rowheight;value2 += 2;const [maxValue, setMaxValue] = useState(value2);let rowHeight = 0;const elementArrary2 = Array.prototype.slice.call(document.getElementsByClassName('tr')) as HTMLDivElement[];rowHeight = elementArrary2[0].clientHeight;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); } } }};
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
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