写在前面
早上我查了很多瀑布流实现的方法,展示逻辑都不是很喜欢。
纸鹤给我看了一个使用了瀑布流布局的网页,网页利用transform
对每个条目进行定位……恍然大悟。
中午做饭的时候看了B站一up主的瀑布流实现视频(麦克阿瑟还是有点实力的),大概知道怎样实现了。
瀑布流布局雏形
思路
用一个定长数组存放第n列某行条目的top值,每次便利找最小top值所在元素,添加一条新条目,并更新top值。等我去画个图。
不完整的代码(仅提供一种思路)
使用react实现,和原生JS有些差别(是哟个原生JS实现可以直接看上面那个视频)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| export defualt testPage() { const boxRef = useRef(null); const [list, setList] = useState([]) const [imagesLoaded, setImagesLoaded] = useState(0); useEffect(() => { getList(); }, []) useEffect(() => { imagesLoaded === list?.length && layout(); }, [imagesLoaded, list]); useEffect(() => { const resizeObserver = new ResizeObserver((entries) => { for (let entry of entries) { layout(); } });
if (boxRef.current) { resizeObserver.observe(boxRef.current); }
return () => { resizeObserver.disconnect(); }; }, [boxRef.current]); funciton layout() { const box = boxRef.current; function getInfo() { let boxWidth = box.offsetWidth; let col = Math.floor(boxWidth / cardWidth); return { boxWidth, col, gap, } } function getMinTop(nextTop) { let min = nextTop[0], minIdx = 0; for (let i = 0, len = nextTop.length; i < len; i++) { } return { min, minIdx } } function getMaxTop() {} let info = getInfo() let nextTop = new Array(info.col).fill(0); for (let i = 0, len = box.children.length; i < len; i++ { const card = box.children[i]; let minTop = getMinTop(nextTop); const dirstX = 0; card.style.transform = `translate(${ firstX + minTop.minIdx * (cardWidth + info.gap) }px, ${ minTop.min + info.gap / 2 }px)`; nextTop[minTop.minIdx] = nextTop[minTop.minIdx] + card.offsetHeight + info.gap; let maxTop = getMaxTop(nextTop); box.style.height = maxTop.max + 'px'; } } return ( <div> <ul className="w-full relative"> {list.map(item => ( <div key={} className={absolute transition-all w-[]}> <CardItem /> </div> ))} </ul> </div> ) }
|
结合无限列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| const [curPage, setCurPage] = useState(0); const [totalPages, setTotalPages] = useState(1); const containerRef = useRef(contianerRef)
function handleScroll() { if (!contianerRef?.current) return; const current = containerRef.current; if (current.scrollTop === 0) { } else if ( current.scrollTop + current.clientHeight === current.scrollHeight ) { if (curPage >= totalPages) { return; } else { setCurPage(curPage + 1); } } }
useEffect(() => { if (curPage > totalPages) { return; } getList(); }, [curPage]);
return ( <div ref={containerRef} className='h-full w-full flex flex-col overflow-x-hidden overflow-y-auto' onScroll={handleScroll} > <div> {list && ( <ul> {list.map(item) => (<div key={}>...</div>)} </ul> )} </div> </div> )
|
实现中:抽成瀑布流无线列表组件
求交流各种妙的实现方法!