CSS问题:如何实现瀑布流布局?

前端功能问题系列文章,点击上方合集↑

序言

大家好,我是大澈!

本文约2500+字,整篇阅读大约需要4分钟。

本文主要内容分三部分,如果您只需要解决问题,请阅读第一、二部分即可。如果您有更多时间,进一步学习问题相关知识点,请阅读至第三部分。

感谢关注微信公众号:“程序员大澈”,然后加入问答群,从此让解决问题的你不再孤单!

1. 需求分析

在电商前台项目中,使用瀑布流的布局形式,展示商品图片列表。

让用户在浏览商品列表时,总有商品图片看不全,使用户可以无限滚动地查看列表下面的其它商品内容。

进而提高用户浏览量,增加商品曝光度,最终提升用户购买几率。

2. 实现步骤

2.1 什么是瀑布流布局呢

瀑布流布局,是页面上是一种参差不齐的多栏布局。

随着页面滚动条向下滚动,这种布局会不断加载新的数据内容,并附加至当前高度最低列的尾部。

它的特点是:布局宽度一致,高度不一致,上下错落排列。一般用于图片内容的展示。

2.2 代码实现

模版代码:

一行要展示几条数据,就定义几个column元素。这里以三列为例。

<template><div class="page-main"><div class="card"><div class="coloum1"><divclass="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"><divclass="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"><divclass="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>

逻辑代码:

第一次渲染时,先把已有数据按顺序正常展示。

然后利用nextTick钩子,在第二次渲染时,先获取所有元素,再循环遍历所有元素,再从第二行第一个元素开始,计算每一列高度和的最小值,把新数据放到最小高度列的数组数据中。以此类推,判断完所有已获取元素。

这里在两次渲染之间,可能会出现页面闪烁现象,所以做了元素显示隐藏的样式处理。

再就是,有多少列,则定义多少新的空数组。这里以三列为例。

<script setup>
import { ref, onMounted, reactive, nextTick } from "vue";// 展示数据
const cardList = reactive([{num: "1号 100px",color: "#3498db",height: "100px",},{num: "2号 200px",color: "#2ecc71",height: "200px",},{num: "3号 60px",color: "#27ae60",height: "60px",},{num: "4号 80px",color: "#e67e22",height: "80px",},{num: "5号 60px",color: "#e74c3c",height: "60px",},{num: "6号 200px",color: "#7f8c8d",height: "200px",},
]);// 由于渲染时候对数据的两次赋值,则会出现一次闪烁,需要做显示隐藏处理
const isVisibility = ref(true);onMounted(() => {// 第一次渲染赋值equallyCard();// 第二次渲染赋值nextTick(() => {caLFlex();}).then(() => {// 闪烁显示隐藏处理isVisibility.value = true;});
});// 各列的展示数据
const cardList1 = ref([]);
const cardList2 = ref([]);
const cardList3 = ref([]);// 第一次渲染赋值
function equallyCard() {// 平分3列的数据,确保页面上遍历卡片dom的真实顺序与平分的一致let num = parseInt(cardList.length / 3);cardList.forEach((item, index) => {if (index < num) {cardList1.value.push(item);return;}if (index < 2 * num) {cardList2.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((accumulator, currentValue) => accumulator + currentValue): 0; // 第一列的总高度const heightTotal_2 = heightArry_2.length? Array.from(heightArry_2).reduce((accumulator, currentValue) => accumulator + currentValue): 0; // 第二列的总高度const heightTotal_3 = heightArry_3.length? Array.from(heightArry_3).reduce((accumulator, currentValue) => accumulator + currentValue): 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]);break;case heightTotal_2:heightArry_2.push(item.offsetHeight);arr2.push(cardList[index]);break;case heightTotal_3:heightArry_3.push(item.offsetHeight);arr3.push(cardList[index]);break;}});// 重新将数据赋值给各列数组cardList1.value = arr1;cardList2.value = arr2;cardList3.value = arr3;
}
</script>

样式代码:

使用了flex布局来做行的排版。这里根据个人项目实际需求自定义即可。

<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>

3. 问题详解

3.1 关于NextTick的个人拙见

作用:等待DOM更新后,再执行内部传入的回调函数

使用场景:  

  • created中想要获取DOM

  • 响应式数据变化后获取DOM更新后的状态,如 获取列表更新后的高度

原理: 把nextTick回调方法放在renderWatcher回调之后执行,这样就能拿到更新后的DOM

3.2 瀑布流其它实现方式

关于瀑布流的实现方式,网上真的是五花八门,各种方法都有。

但因为精力有限,其它方式我也没有再去尝试,只挑选了这么一种比较常用的实现方式,也就是flex布局+js动态计算列高度的方式。我觉的这种方式就足够了,尝试用着还不错。

当然,本次实现的代码,不会是大澈个人空想而来,一定是站在了某位大佬的肩膀之上,又加上了一些个人的理解和拙见,才分享给了朋友们。

最后,也放上参考大佬的文章地址,大佬各种实现方式讲的挺全的,供大家参考:http://d5rhe.jbdi.cn/7b

结语

建立这个平台的初衷:

  • 打造一个仅包含前端问题的问答平台,让大家高效搜索处理同样问题。

  • 通过不断积累问题,一起练习逻辑思维,并顺便学习相关的知识点。

  • 遇到难题,遇到有共鸣的问题,一起讨论,一起沉淀,一起成长。

感谢关注微信公众号:“程序员大澈”,然后加入问答群,从此让解决问题的你不再孤单!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/179239.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaEE进阶学习:Bean 作用域和生命周期

1.Bean 作用域 .通过一个案例来看 Bean 作用域的问题 假设现在有一个公共的 Bean&#xff0c;提供给 A 用户和 B 用户使用&#xff0c;然而在使用的途中 A 用户却“悄悄”地修改了公共 Bean 的数据&#xff0c;导致 B 用户在使用时发生了预期之外的逻辑错误。 我们预期的结果…

colab notebook导出为PDF

目录 方法一&#xff1a;使用浏览器打印功能 方法二&#xff1a;使用nbconvert转换 方法三&#xff1a;在线转换 方法一&#xff1a;使用浏览器打印功能 一般快捷键是CTRLP 然后改变目标打印机为另存为PDF 这样就可以将notebook保存为PDF了 方法二&#xff1a;使用nbconver…

芯片技术前沿:了解构现代集成电路的设计与制造

芯片技术前沿&#xff1a;解构现代集成电路的设计与制造 摘要&#xff1a;本文将深入探讨芯片技术的最新进展&#xff0c;重点关注集成电路的设计与制造。我们将带领读者了解芯片设计的基本流程&#xff0c;包括电路分析、版图设计和验证等步骤&#xff0c;并介绍当前主流的制…

强化学习中的深度Q网络

深度 Q 网络&#xff08;Deep Q-Network&#xff0c;DQN&#xff09;是一种结合了深度学习和强化学习的方法&#xff0c;用于解决离散状态和离散动作空间的强化学习问题。DQN 的核心思想是使用深度神经网络来近似 Q 函数&#xff0c;从而学习复杂环境中的最优策略。 以下是 DQN…

从苹果到蔚来,「车手互联」网罗顶级玩家

作者 |Amy 编辑 |德新 汽车作为家之外的第二大移动空间&#xff0c;正与手机这一移动智能终端进行「车手互联」。 车手互联始于十年前的苹果CarPlay&#xff0c;一度成为时代弄潮儿&#xff0c;不断有后继者模仿并超越。时至今日&#xff0c;CarPlay2.0依旧停留在概念阶段&am…

RK3568笔记六:基于Yolov8的训练及部署

若该文为原创文章&#xff0c;转载请注明原文出处。 基于Yolov8的训练及部署&#xff0c;参考鲁班猫的手册训练自己的数据集部署到RK3568,用的是正点的板子。 1、 使用 conda 创建虚拟环境 conda create -n yolov8 python3.8 ​ conda activate yolov8 2、 安装 pytorch 等…

osgFX扩展库-异性光照、贴图、卡通特效(1)

本章将简单介绍 osgFX扩展库及osgSim 扩展库。osgFX库用得比较多,osgSim库不常用&#xff0c;因此&#xff0c;这里只对这个库作简单的说明。 osgFX扩展库 osgFX是一个OpenSceneGraph 的附加库&#xff0c;是一个用于实现一致、完备、可重用的特殊效果的构架工具&#xff0c;其…

UE 事件分发机制 day9

观察者模式原理 观察者模式通常有观察者与被观察者&#xff0c;当被观察者状态发生改变时&#xff0c;它会通知所有的被观察者对象&#xff0c;使他们能够及时做出响应&#xff0c;所以也被称作“发布-订阅模式”。总得来说就是你关注了一个主播&#xff0c;主播的状态改变会通…

Fabric:搭建自定义网络

Hyperledger Fabric: V2.5.4 写在最前 从本篇博客开始&#xff0c;将陆续介绍使用Fabric搭建自定义网络及部署执行链码的过程。本篇主要介绍如何搭建网络。   由于前文在安装Fabric的时候&#xff0c;已经将目录fabric-samples/bin加入到了环境变量PATH中&#xff0c;所以正文…

数据结构 / day01 作业

1.定义结构体数组存储5个学生的信息&#xff1a;姓名&#xff0c;年龄&#xff0c;性别 定义函数实现输入&#xff0c;要求形参使用结构体指针接收 函数实现5个学生年龄排序(注意对年龄排序时&#xff0c;交换的是所有信息) 定义函数实现输出&#xff0c;要求形参使用结构体…

(5h)Unity3D快速入门之Roll-A-Ball游戏开发

DAY1&#xff1a;Unity3D安装 链接 DAY2&#xff1a;构建场景&#xff0c;编写代码 链接 内容&#xff1a;WASD前后左右移动、摄像机跟随 DAY3&#xff1a;待更新 DAY4&#xff1a;待更新 DAY5&#xff1a;待更新

jekins CVE-2018-1000861 漏洞复现

jekins CVE-2018-1000861 漏洞复现 ‍ 名称: jenkins 命令执行 &#xff08;CVE-2018-1000861&#xff09; 描述: ​Jenkins 可以通过其网页界面轻松设置和配置,其中包括即时错误检查和内置帮助。 插件 通过更新中心中的 1000 多个插件,Jenkins 集成了持续集成和持续交付工具…

INFINI Gateway 与华为鲲鹏完成产品兼容互认证

何为华为鲲鹏认证 华为鲲鹏认证是华为云围绕鲲鹏云服务&#xff08;含公有云、私有云、混合云、桌面云&#xff09;推出的一项合作伙伴计划&#xff0c;旨在为构建持续发展、合作共赢的鲲鹏生态圈&#xff0c;通过整合华为的技术、品牌资源&#xff0c;与合作伙伴共享商机和利…

AI大模型相关产品的数据飞轮如何建设?

1、背景 数据飞轮&#xff0c;是今年大模型带火的一个典型词汇&#xff0c;通过客户在应用程序中输入的提示词这样的数据反馈&#xff0c;使大模型快速迭代。简单说&#xff1a;好的产品 -> 更多的用户数据 -> 更好的模型质量 -> 更好的产品就进入了一个正向循环。一…

【Apifox】测试工具自动编写接口文档

在开发过程中&#xff0c;我们总是避免不了进行接口的测试&#xff0c; 而相比手动敲测试代码&#xff0c;使用测试工具进行测试更为便捷&#xff0c;高效 今天发现了一个非常好用的接口测试工具Apifox 相比于Postman&#xff0c;他还拥有一个非常nb的功能&#xff0c; 在接…

小白备战蓝桥杯:Java基础语法

一、注释 IDEA注释快捷键&#xff1a;Ctrl / 单行注释&#xff1a; //注释信息 多行注释&#xff1a; /* 注释信息 */ 二、字面量 常用数据&#xff1a;整数、小数、字符串&#xff08;双引号&#xff09;、字符&#xff08;单引号&#xff09;、布尔值&#xff08;tr…

JavaScript 的 DOM 知识点有哪些?

文档对象模型&#xff08;Document Object Model&#xff0c;简称 DOM&#xff09;&#xff0c;是一种与平台和语言无关的模型&#xff0c;用来表示 HTML 或 XML 文档。文档对象模型中定义了文档的逻辑结构&#xff0c;以及程序访问和操作文档的方式。 当网页加载时&#xff0…

unity3d 旋转cube时变形

将cube移到父路径同级&#xff0c;重置再&#xff0c;更改角度&#xff0c;或者将父路径先重置&#xff0c;再将cube移动到父节点下面

Corel产品注册机Corel Products KeyGen 2023 – XFORCE解决会声会影2023试用30天

CorelDRAW注册机2023支持全系列产品_Corel Products KeyGen 2023 X-FORCE v8 CorelDRAW注册机2023支持全系列产品_Corel Products KeyGen 2023 X-FORCE v8&#xff0c;Corel产品注册机&#xff08;Corel Products KeyGen 2023 – XFORCE&#xff09;&#xff0c;支持Corel旗下所…

Django请求生命周期流程

浏览器发起请求。 先经过网关接口&#xff0c;Django自带的是wsgiref&#xff0c;请求来的时候解析封装&#xff0c;响应走的时候打包处理&#xff0c;这个wsgiref模块本身能够支持的并发量很少&#xff0c;最多1000左右&#xff0c;上线之后会换成uwsgi&#xff0c;并且还会加…