鸿蒙OSUniApp 制作动态加载的瀑布流布局#三方框架 #Uniapp
使用 UniApp 制作动态加载的瀑布流布局
前言
最近在开发一个小程序项目时,遇到了需要实现瀑布流布局的需求。众所周知,瀑布流布局在展示不规则尺寸内容(如图片、商品卡片等)时非常美观和实用。但在实际开发过程中,我发现普通的 flex 或 grid 布局很难满足这一需求,尤其是当需要配合上拉加载更多功能时,更是增加了实现难度。
经过一番摸索和实践,我总结出了一套在 UniApp 中实现动态加载瀑布流布局的方案,希望能给大家提供一些参考和帮助。
瀑布流布局原理
瀑布流布局的核心思想是:将元素按照自上而下的方式依次排列,但不是简单地一列一列排,而是始终将新元素放置在当前高度最小的那一列,这样就能保证各列高度尽可能接近,整体视觉效果更加协调。
技术实现思路
在 UniApp 中实现瀑布流布局,我尝试过以下几种方案:
- 使用原生 CSS 的 column 属性
- 使用 flex 布局模拟
- 使用 JavaScript 计算每个元素的位置
最终我选择了第三种方案,因为它具有最好的兼容性和最大的灵活性,特别是在处理动态加载数据时。
具体实现步骤
1. 页面结构设计
首先,我们需要创建一个基本的页面结构:
<template><view class="waterfall-container"><view class="waterfall-column" v-for="(column, columnIndex) in columns" :key="columnIndex"><view class="waterfall-item" v-for="(item, itemIndex) in column" :key="item.id"@click="handleItemClick(item)"><image class="item-image" :src="item.imageUrl" :style="{ height: item.height + 'rpx' }"mode="widthFix"@load="onImageLoad(item, columnIndex, itemIndex)"/><view class="item-content"><text class="item-title">{{ item.title }}</text><view class="item-info"><text class="item-price">¥{{ item.price }}</text><text class="item-likes">{{ item.likes }}赞</text></view></view></view></view></view>
</template>
2. 数据结构和状态管理
<script>
export default {data() {return {columns: [[], []], // 默认两列瀑布流columnHeights: [0, 0], // 记录每列的当前高度page: 1,loading: false,hasMore: true,dataList: []};},onLoad() {this.loadInitialData();},// 上拉加载更多onReachBottom() {if (this.hasMore && !this.loading) {this.loadMoreData();}},methods: {async loadInitialData() {this.loading = true;try {const result = await this.fetchData(1);this.dataList = result.data;this.arrangeItems(this.dataList);this.hasMore = result.hasMore;this.page = 1;} catch (error) {console.error('加载数据失败:', error);uni.showToast({title: '加载失败,请重试',icon: 'none'});} finally {this.loading = false;}},async loadMoreData() {if (this.loading) return;this.loading = true;uni.showLoading({title: '加载中...'});try {const nextPage = this.page + 1;const result = await this.fetchData(nextPage);if (result.data && result.data.length > 0) {this.dataList = [...this.dataList, ...result.data];this.arrangeItems(result.data);this.page = nextPage;this.hasMore = result.hasMore;} else {this.hasMore = false;}} catch (error) {console.error('加载更多数据失败:', error);uni.showToast({title: '加载失败,请重试',icon: 'none'});} finally {this.loading = false;uni.hideLoading();}},// 模拟从服务器获取数据fetchData(page) {return new Promise((resolve) => {setTimeout(() => {// 模拟数据,实际项目中应该从服务器获取const mockData = Array.from({ length: 10 }, (_, i) => ({id: page * 100 + i,title: `商品${page * 100 + i}`,price: Math.floor(Math.random() * 1000 + 100),likes: Math.floor(Math.random() * 1000),imageUrl: `https://picsum.photos/200/300?random=${page * 100 + i}`,height: Math.floor(Math.random() * 200 + 200) // 随机高度,让瀑布流效果更明显}));resolve({data: mockData,hasMore: page < 5 // 模拟只有5页数据});}, 1000);});},// 核心算法:将新项目添加到高度最小的列中arrangeItems(items) {items.forEach(item => {// 找出当前高度最小的列const minHeightIndex = this.columnHeights.indexOf(Math.min(...this.columnHeights));// 将项目添加到该列this.columns[minHeightIndex].push(item);// 更新该列的高度(这里用item.height加上内容区域的估计高度)this.columnHeights[minHeightIndex] += (item.height + 120); // 120是内容区域的估计高度});},// 图片加载完成后,调整列高度计算onImageLoad(item, columnIndex, itemIndex) {// 这里可以根据实际加载后的图片高度重新计算列高度// 真实项目中可能需要获取图片实际渲染高度console.log('图片加载完成', item.id);},handleItemClick(item) {uni.navigateTo({url: `/pages/detail/detail?id=${item.id}`});}}
};
</script>
3. 样式设计
<style lang="scss">
.waterfall-container {display: flex;padding: 20rpx;box-sizing: border-box;background-color: #f5f5f5;
}.waterfall-column {flex: 1;display: flex;flex-direction: column;&:first-child {margin-right: 10rpx;}&:last-child {margin-left: 10rpx;}
}.waterfall-item {background-color: #ffffff;border-radius: 12rpx;margin-bottom: 20rpx;overflow: hidden;box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);transition: transform 0.3s;&:active {transform: scale(0.98);}
}.item-image {width: 100%;display: block;
}.item-content {padding: 16rpx;
}.item-title {font-size: 28rpx;color: #333;margin-bottom: 12rpx;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 2;overflow: hidden;text-overflow: ellipsis;
}.item-info {display: flex;justify-content: space-between;align-items: center;
}.item-price {font-size: 32rpx;color: #ff4b2b;font-weight: bold;
}.item-likes {font-size: 24rpx;color: #999;
}
</style>
优化与进阶
1. 图片懒加载
为了优化性能,特别是在图片较多的情况下,我们可以实现图片的懒加载功能。UniApp提供了lazyLoad
属性,配合scrollview
可以很容易实现:
<image class="item-image" :src="item.imageUrl" :style="{ height: item.height + 'rpx' }"mode="widthFix"lazy-load@load="onImageLoad(item, columnIndex, itemIndex)"
/>
2. 列数动态调整
针对不同屏幕尺寸,我们可以动态调整瀑布流的列数:
data() {return {columns: [],columnHeights: [],columnCount: 2, // 默认列数// 其他数据...};
},
onLoad() {// 获取设备信息,动态设置列数const systemInfo = uni.getSystemInfoSync();// 如果是平板等大屏设备,可以显示更多列if (systemInfo.windowWidth > 768) {this.columnCount = 3;}// 初始化列数据this.columns = Array.from({ length: this.columnCount }, () => []);this.columnHeights = Array(this.columnCount).fill(0);this.loadInitialData();
}
3. 下拉刷新
结合UniApp的下拉刷新功能,我们可以很容易实现列表刷新:
// 页面配置
export default {enablePullDownRefresh: true,// ...其他配置
}// 方法实现
onPullDownRefresh() {this.resetAndReload();
},resetAndReload() {// 重置数据this.columns = Array.from({ length: this.columnCount }, () => []);this.columnHeights = Array(this.columnCount).fill(0);this.page = 1;this.hasMore = true;this.dataList = [];// 重新加载this.loadInitialData().then(() => {uni.stopPullDownRefresh();});
}
实际应用案例
我在一个电商类小程序的商品列表页面应用了这种瀑布流布局,效果非常好。用户反馈说浏览商品时比传统的列表更加舒适,能够在同一屏幕内看到更多不同的商品,提升了浏览效率。
特别是对于衣服、家居用品等视觉信息很重要的商品,瀑布流布局可以根据商品图片的实际比例来展示,避免了固定比例裁剪可能带来的信息丢失,商品展示效果更佳。
遇到的问题与解决方案
1. 图片加载速度不一致导致布局跳动
问题:由于网络原因,图片加载速度可能不一致,导致已计算好位置的元素在图片加载后发生位置变化。
解决方案:预设图片高度,或者使用骨架屏占位,在图片完全加载后再显示真实内容。
<view class="waterfall-item"><view v-if="!item.imageLoaded" class="skeleton-image" :style="{ height: item.height + 'rpx' }"></view><image v-elseclass="item-image" :src="item.imageUrl" :style="{ height: item.height + 'rpx' }"mode="widthFix"/><!-- 内容部分 -->
</view>
2. 性能优化
在数据量很大时,可能会出现性能问题。我的解决方案是:
- 使用虚拟列表,只渲染可见区域的元素
- 分批次添加数据,而不是一次性添加所有数据
- 对于复杂计算,使用防抖和节流技术
// 分批次添加数据
arrangeItemsInBatches(items) {const batchSize = 5;const totalItems = items.length;let processedCount = 0;const processBatch = () => {const batch = items.slice(processedCount, processedCount + batchSize);this.arrangeItems(batch);processedCount += batch.length;if (processedCount < totalItems) {setTimeout(processBatch, 50);}};processBatch();
}
总结
通过在UniApp中实现动态加载的瀑布流布局,我们可以为用户提供更好的视觉体验和浏览效率。这种布局特别适合展示不规则尺寸的内容,如图片、商品卡片等。
实现这种布局的关键在于:
- 正确计算每列的高度并动态分配新元素
- 处理好图片加载和元素高度计算的问题
- 结合动态加载实现无限滚动效果
- 针对性能问题进行优化
希望这篇文章对你在UniApp中实现瀑布流布局有所帮助。如果有任何问题或建议,欢迎在评论区交流讨论!
参考资料
- UniApp官方文档:https://uniapp.dcloud.io/
- 瀑布流布局原理:https://www.w3cplus.com/css/pure-css-create-masonry-layout.html
相关文章:
鸿蒙OSUniApp 制作动态加载的瀑布流布局#三方框架 #Uniapp
使用 UniApp 制作动态加载的瀑布流布局 前言 最近在开发一个小程序项目时,遇到了需要实现瀑布流布局的需求。众所周知,瀑布流布局在展示不规则尺寸内容(如图片、商品卡片等)时非常美观和实用。但在实际开发过程中,我…...

Lightpanda开源浏览器:专为 AI 和自动化而设计的无界面浏览器
一、软件介绍 文末提供程序和源码下载 Lightpanda开源浏览器:专为 AI 和自动化而设计的无界面浏览器; Javascript execution Javascript 执行Support of Web APIs (partial, WIP)支持 Web API(部分、WIP)Compatible with Pla…...

技术文档不完善,如何促进知识传承
建立统一的技术文档规范、引入文档自动化工具、将文档写作融入开发流程、建设团队知识共享文化 是促进知识传承的关键策略。在其中,尤应重视建立统一的技术文档规范,通过标准化文档结构、命名、版本管理等方式,提升文档质量和可维护性&#x…...
LLMs之MCP:2025年5月2日,Anthropic 宣布 Claude 重大更新:集成功能上线,研究能力大幅提升
LLMs之MCP:2025年5月2日,Anthropic 宣布 Claude 重大更新:集成功能上线,研究能力大幅提升 导读:2025年5月2日,Anthropic 宣布 Claude 推出 Integrations 集成功能和增强型高级研究功能。Integrations 基于 …...
Linux基础 -- 在内存中使用chroot修复eMMC
Linux基础 – 在内存中使用chroot修复eMMC 概述 本教程将介绍如何在Linux系统中,使用chroot在内存中构建一个临时系统,并在不依赖原有系统的情况下修复eMMC(如/dev/mmcblk2)磁盘。该方法适用于嵌入式系统修复、磁盘清理以及离线…...

Windows平台OpenManus部署及WebUI远程访问实现
前言:继DeepSeek引发行业震动后,Monica.im团队最新推出的Manus AI 产品正席卷科技圈。这款具备自主思维能力的全能型AI代理,不仅能精准解析复杂指令并直接产出成果,更颠覆了传统人机交互模式。尽管目前仍处于封闭测试阶段…...

位运算题目:找到最接近目标值的函数值
文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题:找到最接近目标值的函数值 出处:1521. 找到最接近目标值的函数值 难度 8 级 题目描述 要求 Winston 构造了一个如上所示的函数 func \…...

哲学物理:太极图和莫比乌斯环有什么关系?
太极图 是中国传统文化中的经典符号,由阴阳两部分组成,黑白两色相互环绕,中间有两点表示阴中有阳,阳中有阴。太极图象征着对立统一、相互依存和动态平衡,是道家哲学的核心思想之一。 
机器学习笔记1
一、 机器学习介绍与定义 1. 机器学习定义 机器学习(Machine Learning)本质上就是让计算机自己在数据中学习规律,并根据所得到的规律对未来数据进行预测。 机器学习包括如聚类、分类、决策树、贝叶斯、神经网络、深度学习(Deep…...

JVM中的安全点是什么,作用又是什么?
JVM中的安全点(Safepoint) 是Java虚拟机设计中的一个关键机制,主要用于协调所有线程的执行状态,以便进行全局操作(如垃圾回收、代码反优化等)。它的核心目标是确保在需要暂停所有线程时,每个线程…...

关于github使用总结
文章目录 一、本地使用git(一)创建一个新的本地Git库首先在本地创建一个新的git仓库然后进行一次初始提交提交过后就可以查看提交记录 (二)在本地仓库进行版本恢复先执行 git log 查看项目提交历史使用 git checkout 恢复版本 二、…...
基于Qt6 + MuPDF在 Arm IMX6ULL运行的PDF浏览器——MuPDF Adapter文档
项目地址:总项目Charliechen114514/CCIMXDesktop: This is a Qt Written Desktop with base GUI Utilities 本子项目地址:CCIMXDesktop/extern_app/pdfReader at main Charliechen114514/CCIMXDesktop 前言 这个部分说的是Mupdf_adaper下的文档的工…...
google-Chrome常用插件
google-Chrome常用插件 1. json格式化展示插件 github下载jsonview-for-chrome插件 通过离线安装方式 拓展程序-》管理拓展程序-》打开开发者模式-》加载已解压的拓展程序-》选择拓展程序解压的位置 2. 翻译插件 插件下载地址:Immersive Translate - Bilingual …...

2024年9月电子学会等级考试五级第三题——整数分解
题目 3、整数分解 正整数 N 的 K-P 分解是指将 N 写成 K 个正整数的 P 次方的和。本题就请你对任意给定的正整数 N、K、P,写出 N 的 K-P 分解。 时间限制:8000 内存限制:262144 输入 输入在一行给出 3 个正整数 N (≤ 400)、K (≤ N)、P (1 …...

毕设设计 | 管理系统图例
文章目录 环素1. 登录、注册2. 菜单管理 环素 1. 登录、注册 2. 菜单管理 公告通知 订单管理 会员管理 奖品管理 新增、编辑模块...
u3d 定义列表详细过程
层级结构 - Canvas - Scroll View - Viewport - Content (Vertical Layout Group) - Item1 (Prefab) - Item2 (Prefab) ... 详细设置步骤 1. 创建 Canvas 2. 添加 Scroll View 组件 3. 在 Scroll View 下创建 Content 子对象 4. 添加 …...
使用 `perf` 和火焰图(Flame Graph)进行性能分析
在现代软件开发中,性能优化是提升应用程序响应速度和资源利用率的关键步骤。当一个进程的 CPU 占用率异常高时,识别并优化性能瓶颈显得尤为重要。本文将详细介绍如何使用 Linux 下强大的性能分析工具 perf 以及火焰图(Flame Graph)…...

什么情况会导致JVM退出?
大家好,我是锋哥。今天分享关于【什么情况会导致JVM退出?】面试题。希望对大家有帮助; 什么情况会导致JVM退出? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 JVM(Java虚拟机)退出的情况通常是…...

实验6 电子邮件
实验6 电子邮件 1、实验目的 理解电子邮件系统基本结构 理解客户端和服务器端,以及服务器之间的通信 分析理解SMTP,POP3协议 2、实验环境 硬件要求:阿里云云主机ECS 一台。 软件要求:Linux/ Windows 操作系统 3、实验内容…...
AI大模型从0到1记录学习numpy pandas day24
第 1 章 环境搭建 1.1 Anaconda 1.1.1 什么是Anaconda Anaconda官网地址:https://www.anaconda.com/ 简单来说,Anaconda Python 包和环境管理器(Conda) 常用库 集成工具。它适合那些需要快速搭建数据科学或机器学习开发环境的用…...

深入理解浏览器渲染引擎:底层机制与性能优化实战
现代浏览器背后是一个庞大而复杂的系统工程,渲染引擎作为核心模块之一,承担着从解析 HTML/CSS 到最终绘制页面的关键职责。本文将从底层机制出发,系统梳理渲染引擎(如 Blink)工作原理、V8 与渲染流程的协作方式&#x…...

大模型浪潮下,黑芝麻智能高性能芯片助力汽车辅助驾驶变革
在全球汽车产业向智能化、网联化加速转型的浪潮中,大模型技术的崛起为汽车领域带来了前所未有的变革机遇。黑芝麻智能在高性能芯片和基础软件架构领域的持续创新,正全力推动汽车智能化的发展,为行业注入新的活力。 大模型全面助力辅助驾驶迈…...
鸿蒙OSUniApp制作多选框与单选框组件#三方框架 #Uniapp
使用UniApp制作多选框与单选框组件 前言 在移动端应用开发中,表单元素是用户交互的重要组成部分。尤其是多选框(Checkbox)和单选框(Radio),它们几乎存在于每一个需要用户做出选择的场景中。虽然UniApp提供…...

康谋分享 | 自动驾驶仿真进入“标准时代”:aiSim全面对接ASAM OpenX
目录 一、OpenDRIVE:兼容多版本地图标准 (1)Atlas 工作流 (2)UE Plugin 工作流 二、OpenSCENARIO:标准化动态行为建模 三、OpenCRG:还原毫米级路面细节 四、OpenMATERIAL:更真…...
VMware中快速安装与优化Ubuntu全攻略
准备工作 在开始安装之前,确保已经下载了VMware Workstation或VMware Player,并准备好Ubuntu的ISO镜像文件。VMware Workstation是一款功能强大的虚拟机软件,支持在Windows或Linux主机上运行多个操作系统。 创建虚拟机 打开VMware Worksta…...

GPUGeek云平台实战:DeepSeek-R1-70B大语言模型一站式部署
随着人工智能技术的迅猛发展,特别是在自然语言处理领域,大型语言模型如DeepSeek-R1-70B的出现,推动了各行各业的变革。为了应对这些庞大模型的计算需求,云计算平台的普及成为了关键,特别是基于GPU加速的云平台…...
无人机动力系统全解析:核心组件、工作原理与实用指南
无人机想要实现稳定飞行与灵活操控,离不开一套高效协同的动力系统。该系统以电机、电子调速器(电调)、电池和螺旋桨四大核心组件为基础,各部分精密配合,共同驱动无人机翱翔蓝天。接下来,本文将从基础原理入…...

【C语言】初阶数据结构相关习题(二)
🎆个人主页:夜晚中的人海 今日语录:知识是从刻苦劳动中得来的,任何成就都是刻苦劳动的结果。——宋庆龄 文章目录 🎄一、链表内指定区间翻转🎉二、从链表中删去总和值为零的节点🚀三、链表求和&…...

嵌入式学习--江科大51单片机day7
我们在听课的过程中,可能对老师讲的有疑问,或者有些自己的理解,我们可以去问豆包,包括在写博客的时候我也是,不断去问豆包保证思考的正确性。(有人感觉豆包很low啊,其实这些基础性的东西豆包一般…...
基于大模型预测围术期麻醉苏醒时间的技术方案
目录 一、数据收集与处理(一)数据来源(二)数据预处理二、大模型构建与训练(一)模型选择(二)模型训练三、围术期麻醉苏醒时间预测(一)术前预测(二)术中动态预测四、并发症风险预测(一)风险因素分析(二)风险预测模型五、基于预测制定手术方案(一)个性化手术规划…...