写在前面
早上我查了很多瀑布流实现的方法,展示逻辑都不是很喜欢。
纸鹤给我看了一个使用了瀑布流布局的网页,网页利用transform对每个条目进行定位……恍然大悟。
中午做饭的时候看了B站一up主的瀑布流实现视频(麦克阿瑟还是有点实力的),大概知道怎样实现了。
瀑布流布局雏形
思路
用一个定长数组存放第n列某行条目的top值,每次便利找最小top值所在元素,添加一条新条目,并更新top值。等我去画个图。

不完整的代码(仅提供一种思路)
使用react实现,和原生JS有些差别(是哟个原生JS实现可以直接看上面那个视频)
| 12
 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>
 )
 }
 
 | 
结合无限列表
| 12
 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>
 )
 
 | 
实现中:抽成瀑布流无线列表组件
求交流各种妙的实现方法!