文章目录
一、 什么是瀑布流布局1.是什么2.特点 二、有什么优缺点1.优点2.缺点 三、实现方法法一、纯css的写法:【multi-column 多栏布局】1.两个重要属性2.特点3.缺点4.注意点:
SEO靠我5.实现的代码模式(以下用vue3.0来书写) 法二、泳道的思想:【用flex弹性布局+计算元素高度实现布局】1.原理的分析2.算法思路:通过上面的分析则能了解瀑布流的思路了3.代码实现思路4.代码实
SEO靠我现(以下用vue3.0来实现) 法三、绝对定位实现:【精确计算每个子元素绝对定位到瀑布流它应该去的地方,需要后期一些优化,并不推荐使用】1.缺点2.实现的原理3.代码实现思路4.代码实现(vue3.0
SEO靠我来实现) 法四、插件实现:【用插件vue-waterfall2 不是很建议使用,一般用于图片的加载,但是复杂的业务就不是很ok了】1.安装依赖2.引入3.相关api4.代码实现
一、 什么是瀑布流布局
页面上是一种 参差不齐 的多栏布局,类似上图所示随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部,大部分为图片,图片 固定 宽度,高度 不一,根据原比例缩放到宽度达到固定的要
SEO靠我求,每行排满后,新的图片添加到后面
2.特点
固定宽度,高度不一 岑参不齐的布局以图片为主
二、有什么优缺点
1.优点
节省空间:降低页面的复杂对于 触屏设备非常友好:通过向上滑动浏览,交互方式更符合直觉良好的
SEO靠我视觉体验:浏览时不会被页面整整齐齐的高度影响,参差不齐,降低浏览的疲劳
2.缺点
内容总长度 无法掌握数据过多时,容易造成页面 加载的负荷再次加载时 很难定位上一次浏览的内容
三、实现方法
法一、纯css的写SEO靠我法:【multi-column 多栏布局】
1.两个重要属性
column-count : 定义列数
column-gap :列与列之间的间隔
2.特点
顺序只能是 从上到下, 再左到右
3.缺点
由于排列顺序是先SEO靠我 从上到下, 再左到右,只能用于数据固定,无法动态的加载追加,对于滚动到底部加载新数据则无法实现。
4.注意点:
有时候页面会出现在前几列的最后一个元素的内容被自动断开,一部分在当前列尾,一部分在下一列的SEO靠我列头。这时候子元素可以用 break-inside设置为不被截断 avoid来控制
break-inside: avoid; // 不被截断 默认值是auto,会被截断
5.实现的代码模式(以下用vue3SEO靠我.0来书写)
template
<template><div class="page-main"><div class="card"><div class="card-item" v-f
SEO靠我or="(item,index) in cardList" :key="index" :style="[{background: item.color},{height: item.height},{
SEO靠我lineHeight: item.height}]"><p class="text">{{index}}</p></div></div></div>
</template>
SEO靠我 script
<script setup>
import {ref} from vue
const cardList = ref([ // 模拟
SEO靠我数据{color: #FCCF0A,height: 100px,},......
])
</script>
style multi-column 实现
SEO靠我
<style lang="scss" scoped>
.page-main{background: #ffffff;min-height:100vh;padding:
SEO靠我 0 30px;.card{column-count: 3; // 定义三列column-gap: 20px; // 列与列的距离为20px.card-item{text-align: center;
SEO靠我width: 216px;border-radius: 16px;grid-row-start: auto;margin-bottom: 20px;break-inside: avoid; // 不被
SEO靠我截断}}
}
</style>
法二、泳道的思想:【用flex弹性布局+计算元素高度实现布局】
泳道的概念:通俗的说是类似泳道一样,先设置泳道列数,一列一列的,然后往里加东SEO靠我西,就自动往下面走了。
1.原理的分析
适用范围:基本业务都能实现首先比如有四个元素了,并且设置四列
那么第五个位置在哪里呢
答案: 是下面图的位置上,SEO靠我找到的位置应该高度为所有列中最小的位置
第六个的位置呢,答案还是和上面一样的所示 找到高度为所有列中最小的位置,则为下面的位置
2.算法思路:通过上面的分析则能了解瀑布流的思路SEO靠我了
设计要分成的列数 设置每列的 宽度一致 每次插入的位置选择所有列高度最小 的位置,依次循环
3.代码实现思路
由于需要拿到每个数据的dom元素的实际值,则需要先对数据进行赋值,这样就可以拿到所有的元素d
SEO靠我om上的高度则渲染时候对数据的两次赋值,则会出现一次闪现,需要防抖 ,可以先将卡片设置为visibility:hidden ,当后面对数据处理完,重新渲染后再将卡片设置为visibility:visi
SEO靠我ble 多少列则定义多少新的空数组,然后根据瀑布流的思路依次插入 到空的数组即可,最后再重新渲染页面即可
4.代码实现(以下用vue3.0来实现)
template (例子为三列)
<te
SEO靠我mplate><div class="page-main"><div class="card"><div class="coloum1" ><div class="card-item" v-for="
SEO靠我(item,index) in cardList1" :key="index" :style="[{background: item.color},{height: item.height},{lin
SEO靠我eHeight: item.height}]" :class="{visibles: isVisibility}"><p class="text">{{item.num}}</p></div></di
SEO靠我v><div class="coloum2"><div class="card-item" v-for="(item,index) in cardList2" :key="index" :style=
SEO靠我"[{background: item.color},{height: item.height},{lineHeight: item.height}]" :class="{visibles: isVi
SEO靠我sibility}"><p class="text">{{item.num}}</p></div></div><div class="coloum3"><div class="card-item" v
SEO靠我-for="(item,index) in cardList3" :key="index" :style="[{background: item.color},{height: item.height
SEO靠我},{lineHeight: item.height}]" :class="{visibles: isVisibility}"><p class="text">{{item.num}}</p></di
SEO靠我v></div></div></div>
</template>
js
<script setup>
import {ref,onMo
SEO靠我unted, reactive,nextTick} from vue
const cardList = reactive([ // 测试数据{num: 0,color: #FCCF0A
SEO靠我,height: 100px,}, ...测试数据
])const isVisibility = ref(true)
// 由于渲染时候对数据的两次赋值,则会出现一次闪
SEO靠我现,需要防抖onMounted(()=>{equallyCard()nextTick(()=>{caLFlex()}).then(()=>{isVisibility.value = true})
SEO靠我 })const cardList1 = ref([]) // 各列的数据
const cardList2 = ref([])
const cardList3
SEO靠我 = ref([])function equallyCard(){// 平分数据,确保页面上遍历卡片dom的真实顺序与平分的一致 document.querySelectorAll(.card-ite
SEO靠我m))let num = parseInt(cardList.length/3)cardList.forEach((item,index)=>{if(index<num){cardList1.valu
SEO靠我e.push(item)return}if(index<2*num){cardList1.value.push(item)return}cardList3.value.push(item)})
SEO靠我 }function caLFlex(){let arr1 = [] // 第一列的值let arr2 = [] // 第二列的值let arr3 = [] // 第二列的值let heigh
SEO靠我tArry_1 = [] // 第一列的卡片高度let heightArry_2 = [] // 第二列的卡片高度let heightArry_3 = [] // 第二列的卡片高度Array.from
SEO靠我(document.querySelectorAll(.card-item)).forEach((item,index) =>{if(index === 0){ // 第一行中的元素无需判断,直接加到
SEO靠我新的数组中heightArry_1.push(item.offsetHeight)arr1.push(cardList[index])return}if(index === 1){heightArry
SEO靠我_2.push(item.offsetHeight)arr2.push(cardList[index])return}if(index === 2){heightArry_3.push(item.of
SEO靠我fsetHeight)arr3.push(cardList[index])return}const heightTotal_1 = heightArry_1.length ? Array.from(h
SEO靠我eightArry_1).reduce(( acc, cur ) => acc + cur) : 0 // 第一列的总高度const heightTotal_2 = heightArry_2.leng
SEO靠我th ? Array.from(heightArry_2).reduce(( acc, cur ) => acc + cur) : 0 // 第二列的总高const heightTotal_3 = h
SEO靠我eightArry_3.length ? Array.from(heightArry_3).reduce(( acc, cur ) => acc + cur) : 0 // 第三列的总高度// 找到最
SEO靠我小值let minNumber = Math.min(heightTotal_1,heightTotal_2,heightTotal_3)switch (minNumber) {case height
SEO靠我Total_1:heightArry_1.push(item.offsetHeight)arr1.push(cardList[index])breakcase heightTotal_2:height
SEO靠我Arry_2.push(item.offsetHeight)arr2.push(cardList[index])breakcase heightTotal_3:heightArry_3.push(it
SEO靠我em.offsetHeight)arr3.push(cardList[index])break}})// 重新将数据赋值给各列数组cardList1.value = arr1cardList2.val
SEO靠我ue = arr2cardList3.value = arr3
}
css
<style lang="scss" scoped>
.p
SEO靠我age-main{background: #ffffff;height:100vh;overflow: hidden;padding: 0 30px;.card{display: flex;flex-
SEO靠我direction: row;justify-content: space-around;.card-item{visibility: hidden;margin-bottom: 20px;text-
SEO靠我align: center;width: 216px;border-radius: 16px;}.visibles {visibility: visible;}}
}
SEO靠我</style>
法三、绝对定位实现:【精确计算每个子元素绝对定位到瀑布流它应该去的地方,需要后期一些优化,并不推荐使用】
1.缺点
计算量相比较 大,较复杂会有高度塌陷问题子元素因为设置了 absolut
SEO靠我e并不会占高,页面可滚动的话又会产生另外的问题如果在移动端中会做适配,当前的绝对定位的高度单位在代码实现若为px 并不会自动换算当视口的窗口resize改变,需要重新计算元素的位置,若会不断触发事件,
SEO靠我性能消耗大,加载也慢,这是不可取的
2.实现的原理
通过>精准的计算每个子元素的位置,定位到瀑布流应该去的地方
3.代码实现思路
子元素全部设置成绝对定位找到所有列中>最小的位置计算子元素定位时的 top 以
SEO靠我及left 修改子元素的样式,设置position为absolute ,以及设置top ,left每次插入的位置选择所有列高度最小 的位置,依次循环
4.代码实现(vue3.0来实现)
template
SEO靠我 <template><div class="page-main"><div class="card"><div class="card-item" v-for="(item,index
SEO靠我) in cardList" :key="index" :style="[{background: item.color},{height: item.height},{lineHeight: ite
SEO靠我m.height}]" :class="{visibles: isVisibility}"><p class="text">{{item.num}}</p></div></div></div>
SEO靠我 </template>
script
以下是一些代码说明
1、 coloumHight [0,0] 为两列,coloumHight [0,0,0] 为三列
2、 getMinCo
SEO靠我loumHeight方法: 找到最小列<script setup>
import {onMounted, reactive, ref} from vue
const c
SEO靠我ardList = reactive([ // 测试数据{num: 0,color: #FCCF0A,height: 100px,},...测试数据
])const isVisibil
SEO靠我ity = ref(false)
// 由于渲染时候对数据的两次赋值,则会出现一次闪现,需要防抖onMounted(()=>{caLFlex()
})function
SEO靠我caLFlex(){let coloumHight = [0,0,0] // 每列元素的高度,本例子为3列// 依次插入每个元素Array.from(document.querySelectorAll
SEO靠我(.card-item)).forEach((item,index) =>{let coloum = getMinColoumHeight(coloumHight) // 得到当前所有最小高度的一列l
SEO靠我et itemTop = coloumHight[coloum]let itemLeft = coloum * 200item.style.position = "absolute"item.styl
SEO靠我e.top = `${itemTop}px`item.style.left = `${itemLeft}px`// 当前高度加上新增的元素高度coloumHight[coloum] += item.o
SEO靠我ffsetHeight})isVisibility.value = true
}// 找到所有列中高度最小的一列
function getMinColoumHeight
SEO靠我(arr){let min = Math.min(...arr)return arr.indexOf(min) !== -1 ? arr.indexOf(min) : 0 // 默认第一列
SEO靠我 }
</script>
style
<style lang="scss" scoped>
.page-main{backgrou
SEO靠我nd: #ffffff;height:100vh;overflow: hidden;padding: 0 30px;.card{position: relative;.card-item{width:
SEO靠我 200px;text-align: center;visibility: hidden;}.visibles {visibility: visible;}}
}
</
SEO靠我style>
法四、插件实现:【用插件vue-waterfall2 不是很建议使用,一般用于图片的加载,但是复杂的业务就不是很ok了】
1.安装依赖
npm i vue-waterfall2@latest
SEO靠我--save
2.引入
import waterfall from vue-waterfall2
Vue.use(waterfall)
3.相关api
4.代码实现
<template><div
SEO靠我 class="container-water-fall"><waterfall:col="col":data="data"@scroll="scroll"@finish="finish":heigh
SEO靠我t="100vh"><template><divclass="cell-item"v-for="(item, index) in data":key="index"><img v-if="item.i
SEO靠我mg" :src="item.img" alt="加载错误" /><div class="item-body"><div class="item-desc">{{ item.title }}</div
SEO靠我><div class="item-footer"><divv-if="item.avatar"class="avatar":style="{backgroundImage: `url(${item.
SEO靠我avatar})`,}"></div><div class="name">{{ item.user }}</div><divclass="like":class="item.liked ? activ
SEO靠我e : "><i></i><div class="like-total">{{ item.like }}</div></div></div></div></div></template></water
SEO靠我fall></div>
</template><script>
import json from "./components/data.json";
e
SEO靠我xport default {name: "App",/*注意:1. gutterWidth需要与width一起使用才会生效,否则会进行自适应宽度(使用rem布局时,需先计算出自适应后的宽度再传值)2
SEO靠我. 使用了`waterfall`的父组件,如果样式存在问题,可去掉css `scoped`尝试一下
*/data() {return {data: [{img:"https://ima
SEO靠我ge.watsons.com.cn//upload/8a316140.png?w=377&h=451&x-oss-process=image/resize,w_1080",avatar:"https:
SEO靠我//img.xiaohongshu.com/avatar/5b7d198a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title: "最近浴室新宠,日
SEO靠我系神仙好物了解一下~",user: "迷人的小妖精迷人的小妖精",like: "953",},{img:"https://image.watsons.com.cn//upload/5c3e51e4.j
SEO靠我pg?w=720&h=960&x-oss-process=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d198
SEO靠我a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title: "真的是万能.超级实用.包包必备单品! ! !",user: "迷人的小妖精迷人的小妖精"
SEO靠我,like: "952",},{img:"https://image.watsons.com.cn//upload/bef41e67.JPG?w=712&h=534&x-oss-process=ima
SEO靠我ge/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d198a7e6e15000155f7c9.jpg@80w_80h_90
SEO靠我q_1e_1c_1x.jpg",title: "150元搞定全套护肤品,这些护肤好物必须交出来!",user: "迷人的小妖精迷人的小妖精",like: "953",},{img:"https://i
SEO靠我mage.watsons.com.cn//upload/13afe9a7.jpg?x-oss-process=image/resize,w_1080",avatar:"https://img.xiao
SEO靠我hongshu.com/avatar/5b7d198a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title: "夏天用这款姨妈巾,让你体验真正的清爽
SEO靠我",user: "迷人的小妖精迷人的小妖精",like: "953",},{img:"https://image.watsons.com.cn//upload/642cb83c.jpeg?w=1080
SEO靠我&h=1080&x-oss-process=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d198a7e6e15
SEO靠我000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title:"贵妇级好用的水乳有哪些呢?千万不要去乱尝试贵妇级好用的水乳有哪些呢?千万不要去乱尝试贵妇级好用的水乳有哪
SEO靠我些呢?千万不要去乱尝试",user: "迷人的小妖精迷人的小妖精",like: "953",},{img:"https://image.watsons.com.cn//upload/98c7c4c3.
SEO靠我jpg?w=1210&h=1210&x-oss-process=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d
SEO靠我198a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title:"贵妇级好用的水乳有哪些呢?千万不要去乱尝试贵妇级好用的水乳有哪些呢?千万不要去乱尝试
SEO靠我贵妇级好用的水乳有哪些呢?千万不要去乱尝试",user: "迷人的小妖精迷人的小妖精",like: "953",},{img:"https://image.watsons.com.cn//upload
SEO靠我/25ab20fe.JPG?w=1000&h=1200&x-oss-process=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/a
SEO靠我vatar/5b7d198a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title: "夏天用这款姨妈巾,让你体验真正的清爽",user: "迷人的小
SEO靠我妖精迷人的小妖精",like: "953",},{img:"https://image.watsons.com.cn//upload/083767f0.JPG?w=828&h=620&x-oss-pr
SEO靠我ocess=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d198a7e6e15000155f7c9.jpg@8
SEO靠我0w_80h_90q_1e_1c_1x.jpg",title: "150元搞定全套护肤品,这些护肤好物必须交出来!",user: "迷人的小妖精迷人的小妖精",like: "953",},],col:
SEO靠我 2,};},computed: {itemWidth() {return 138 * 0.5 * (document.documentElement.clientWidth / 375); //re
SEO靠我m布局 计算宽度},gutterWidth() {return 9 * 0.5 * (document.documentElement.clientWidth / 375); //rem布局 计算x轴
SEO靠我方向margin(y轴方向的margin自定义在css中即可)},},methods: {scroll(scrollData) {console.log(scrollData);},switchCol
SEO靠我(col) {this.col = col;console.log(this.col);}},
};
</script><style>
* {margi
SEO靠我n: 0;
}
.cell-item {width: 100%;margin-bottom: 10px;background: #ffffff;border: 2px
SEO靠我solid #f0f0f0;border-radius: 12px 12px 12px 12px;overflow: hidden;box-sizing: border-box;
}
SEO靠我 img {width: 100%;height: auto;display: block;
}
</style>