0


实现瀑布流布局的三种方法

文章目录

一、 什么是瀑布流布局

1、是什么

  • 页面上是一种 参差不齐 的多栏布局,类似上图所示随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部,大部分为图片,图片 固定 宽度,高度 不一,根据原比例缩放到宽度达到固定的要求,每行排满后,新的图片添加到后面

2、特点

  • 固定宽度,高度不一
  • 岑参不齐的布局
  • 以图片为主

二、有什么优缺点

1、优点

  • 节省空间:降低页面的复杂
  • 对于 触屏设备非常友好:通过向上滑动浏览,交互方式更符合直觉
  • 良好的视觉体验:浏览时不会被页面整整齐齐的高度影响,参差不齐,降低浏览的疲劳

2、缺点

  • 内容总长度 无法掌握
  • 数据过多时,容易造成页面 加载的负荷
  • 再次加载时 很难定位上一次浏览的内容

三、实现方法

法一、【multi-column 多栏布局】

在这里插入图片描述

1、两个重要属性

column-count : 定义列数
column-gap :列与列之间的间隔

2、特点

顺序只能是 从上到下, 再左到右

3、缺点

由于排列顺序是先 从上到下, 再左到右,只能用于数据固定,无法动态的加载追加,对于滚动到底部加载新数据则无法实现。

4、注意点:

有时候页面会出现在前几列的最后一个元素的内容被自动断开,一部分在当前列尾,一部分在下一列的列头。这时候子元素可以用 break-inside设置为不被截断 avoid来控制

break-inside: avoid; // 不被截断 默认值是auto,会被截断

5、实现的代码模式(以下用vue3.0来书写)

  • template
<template><div  class="page-main"><div class="card"><div class="card-item" v-for="(item,index) in cardList":key="index":style="[{background: item.color},{height: item.height},{lineHeight: item.height}]"><p class="text">{{index}}</p></div></div></div></template>
  • script
<script setup>
import {ref} from 'vue'
const cardList =ref([// 模拟数据{
    color:  '#FCCF0A',height: '100px',},......])</script>
  • style multi-column 实现
<style lang="scss" scoped>.page-main{
    background: #ffffff;
    min-height:100vh;
    padding:0 30px;.card{
        column-count:3;// 定义三列
        column-gap: 20px;// 列与列的距离为20px.card-item{
        text-align: center;
        width: 216px;
        border-radius: 16px;
        grid-row-start: auto;
        margin-bottom: 20px;break-inside: avoid;// 不被截断}}}</style>

法二、【用flex弹性布局+计算元素高度实现布局】

1、原理的分析

  • 适用范围:基本业务都能实现
  • 首先比如有四个元素了,并且设置四列

在这里插入图片描述

  • 那么第五个位置在哪里呢

在这里插入图片描述

  • 答案: 是下面图的位置上,找到的位置应该高度为所有列中最小的位置

在这里插入图片描述

  • 第六个的位置呢,答案还是和上面一样的所示 找到高度为所有列中最小的位置,则为下面的位置在这里插入图片描述

2、算法思路:通过上面的分析则能了解瀑布流的思路了

  • 设计要分成的列数
  • 设置每列的 宽度一致
  • 每次插入的位置选择所有列高度最小 的位置,依次循环

3、代码实现思路

  • 由于需要拿到每个数据的dom元素的实际值,则需要先对数据进行赋值,这样就可以拿到所有的元素dom上的高度
  • 则渲染时候对数据的两次赋值,则会出现一次闪现,需要防抖 ,可以先将卡片设置为visibility:hidden ,当后面对数据处理完,重新渲染后再将卡片设置为visibility:visible
  • 多少列则定义多少新的空数组,然后根据瀑布流的思路依次插入 到空的数组即可,最后再重新渲染页面即可

4、代码实现(以下用vue3.0来实现)

在这里插入图片描述

  • template (例子为三列)
<template><div  class="page-main"><div class="card"><div class="coloum1"><div class="card-item" v-for="(item,index) in cardList1":key="index":style="[{background: item.color},{height: item.height},{lineHeight: item.height}]":class="{visibles: isVisibility}"><p class="text">{{item.num}}</p></div></div><div class="coloum2"><div class="card-item" v-for="(item,index) in cardList2":key="index":style="[{background: item.color},{height: item.height},{lineHeight: item.height}]":class="{visibles: isVisibility}"><p class="text">{{item.num}}</p></div></div><div class="coloum3"><div class="card-item" v-for="(item,index) in cardList3":key="index":style="[{background: item.color},{height: item.height},{lineHeight: item.height}]":class="{visibles: isVisibility}"><p class="text">{{item.num}}</p></div></div></div></div></template>
  • js
<script setup>import{ref,onMounted, reactive,nextTick} from 'vue'const cardList =reactive([// 测试数据{
    num:'0',
    color:'#FCCF0A',
    height:'100px',},...测试数据
])const isVisibility =ref(true)// 由于渲染时候对数据的两次赋值,则会出现一次闪现,需要防抖onMounted(()=>{equallyCard()nextTick(()=>{caLFlex()}).then(()=>{
    isVisibility.value =true})})const cardList1 =ref([])// 各列的数据const cardList2 =ref([])const cardList3 =ref([])

function equallyCard(){// 平分数据,确保页面上遍历卡片dom的真实顺序与平分的一致 document.querySelectorAll('.card-item'))
  let num =parseInt(cardList.length/3)
  cardList.forEach((item,index)=>{if(index<num){
       cardList1.value.push(item)return}if(index<2*num){
       cardList1.value.push(item)return}
    cardList3.value.push(item)})}

function caLFlex(){
  let arr1 =[]// 第一列的值
  let arr2 =[]// 第二列的值
  let arr3 =[]// 第二列的值
  let heightArry_1 =[]// 第一列的卡片高度
  let heightArry_2 =[]// 第二列的卡片高度
  let heightArry_3 =[]// 第二列的卡片高度
  Array.from(document.querySelectorAll('.card-item')).forEach((item,index)=>{if(index ===0){// 第一行中的元素无需判断,直接加到新的数组中
          heightArry_1.push(item.offsetHeight)
          arr1.push(cardList[index])return}if(index ===1){
          heightArry_2.push(item.offsetHeight)
           arr2.push(cardList[index])return}if(index ===2){
          heightArry_3.push(item.offsetHeight)
          arr3.push(cardList[index])return}const heightTotal_1 = heightArry_1.length ? Array.from(heightArry_1).reduce(( acc, cur )=> acc + cur):0// 第一列的总高度const heightTotal_2 = heightArry_2.length ? Array.from(heightArry_2).reduce(( acc, cur )=> acc + cur):0// 第二列的总高const heightTotal_3 = heightArry_3.length ? Array.from(heightArry_3).reduce(( acc, cur )=> acc + cur):0// 第三列的总高度// 找到最小值
     let minNumber = Math.min(heightTotal_1,heightTotal_2,heightTotal_3)switch(minNumber){case heightTotal_1:
          heightArry_1.push(item.offsetHeight)
          arr1.push(cardList[index])breakcase heightTotal_2:
         heightArry_2.push(item.offsetHeight)
          arr2.push(cardList[index])breakcase heightTotal_3:
         heightArry_3.push(item.offsetHeight)
          arr3.push(cardList[index])break}})// 重新将数据赋值给各列数组
  cardList1.value = arr1
  cardList2.value = arr2
  cardList3.value = arr3
}
  • css
<style lang="scss" scoped>.page-main{
    background: #ffffff;
    height:100vh;
    overflow: hidden;
    padding:0 30px;.card{
        display: flex;
        flex-direction: row;
        justify-content: space-around;.card-item{
          visibility: hidden;
          margin-bottom: 20px;
          text-align: center;
          width: 216px;
          border-radius: 16px;}.visibles {
          visibility: visible;}}}</style>

法三、【用插件vue-waterfall2 不是很建议使用,一般用于图片的加载,但是复杂的业务就不是很ok了】

1、安装依赖

npm i vue-waterfall2@latest --save

2、引入

import waterfall from 'vue-waterfall2'
Vue.use(waterfall)

3、相关api

在这里插入图片描述
在这里插入图片描述

4、代码实现

<template><div class="container-water-fall"><waterfall
            :col="col":data="data"
            @scroll="scroll"
            @finish="finish":height="'100vh'"><template><div
                    class="cell-item"
                    v-for="(item, index) in data":key="index"><img v-if="item.img":src="item.img" alt="加载错误"/><div class="item-body"><div class="item-desc">{{ item.title }}</div><div class="item-footer"><div
                                v-if="item.avatar"class="avatar":style="{
                                    backgroundImage: `url(${item.avatar})`,}"
                            ></div><div class="name">{{ item.user }}</div><div
                                class="like":class="item.liked ? 'active' : ''"><i></i><div class="like-total">{{ item.like }}</div></div></div></div></div></template></waterfall></div></template><script>
import json from"./components/data.json";
export default{
    name:"App",/*
  注意:
  1. gutterWidth需要与width一起使用才会生效,否则会进行自适应宽度(使用rem布局时,需先计算出自适应后的宽度再传值)
  2. 使用了`waterfall`的父组件,如果样式存在问题,可去掉css `scoped`尝试一下
*/data(){return{
            data:[{
                    img:"https://image.watsons.com.cn//upload/8a316140.png?w=377&h=451&x-oss-process=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d198a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title:"最近浴室新宠,日系神仙好物了解一下~",user:"迷人的小妖精迷人的小妖精",like:"953",},{
                    img:"https://image.watsons.com.cn//upload/5c3e51e4.jpg?w=720&h=960&x-oss-process=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d198a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title:"真的是万能.超级实用.包包必备单品! ! !",user:"迷人的小妖精迷人的小妖精",like:"952",},{
                    img:"https://image.watsons.com.cn//upload/bef41e67.JPG?w=712&h=534&x-oss-process=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d198a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title:"150元搞定全套护肤品,这些护肤好物必须交出来!",user:"迷人的小妖精迷人的小妖精",like:"953",},{
                    img:"https://image.watsons.com.cn//upload/13afe9a7.jpg?x-oss-process=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d198a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title:"夏天用这款姨妈巾,让你体验真正的清爽",user:"迷人的小妖精迷人的小妖精",like:"953",},{
                    img:"https://image.watsons.com.cn//upload/642cb83c.jpeg?w=1080&h=1080&x-oss-process=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d198a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title:"贵妇级好用的水乳有哪些呢?千万不要去乱尝试贵妇级好用的水乳有哪些呢?千万不要去乱尝试贵妇级好用的水乳有哪些呢?千万不要去乱尝试",user:"迷人的小妖精迷人的小妖精",like:"953",},{
                    img:"https://image.watsons.com.cn//upload/98c7c4c3.jpg?w=1210&h=1210&x-oss-process=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d198a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title:"贵妇级好用的水乳有哪些呢?千万不要去乱尝试贵妇级好用的水乳有哪些呢?千万不要去乱尝试贵妇级好用的水乳有哪些呢?千万不要去乱尝试",user:"迷人的小妖精迷人的小妖精",like:"953",},{
                    img:"https://image.watsons.com.cn//upload/25ab20fe.JPG?w=1000&h=1200&x-oss-process=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d198a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title:"夏天用这款姨妈巾,让你体验真正的清爽",user:"迷人的小妖精迷人的小妖精",like:"953",},{
                    img:"https://image.watsons.com.cn//upload/083767f0.JPG?w=828&h=620&x-oss-process=image/resize,w_1080",avatar:"https://img.xiaohongshu.com/avatar/5b7d198a7e6e15000155f7c9.jpg@80w_80h_90q_1e_1c_1x.jpg",title:"150元搞定全套护肤品,这些护肤好物必须交出来!",user:"迷人的小妖精迷人的小妖精",like:"953",},],col:2,};},computed:{itemWidth(){return138*0.5*(document.documentElement.clientWidth /375);//rem布局 计算宽度},gutterWidth(){return9*0.5*(document.documentElement.clientWidth /375);//rem布局 计算x轴方向margin(y轴方向的margin自定义在css中即可)},},methods:{scroll(scrollData){
            console.log(scrollData);},switchCol(col){this.col = col;
            console.log(this.col);}},};</script><style>*{
    margin:0;}.cell-item {
    width:100%;
    margin-bottom: 10px;
    background: #ffffff;
    border: 2px solid #f0f0f0;
    border-radius: 12px 12px 12px 12px;
    overflow: hidden;
    box-sizing: border-box;}
img {
    width:100%;
    height: auto;
    display: block;}</style>

本文转载自: https://blog.csdn.net/Smile_666666/article/details/124728121
版权归原作者 Smile_zxx 所有, 如有侵权,请联系我们删除。

“实现瀑布流布局的三种方法”的评论:

还没有评论