当前位置: 首页 > news >正文

<list-view> 和 <waterfall-view> 详解

uni-app x中,<list-view><waterfall-view>是专门为解决大数据量、长列表渲染卡顿/内存暴涨而设计的两个纯原生核心组件

与传统的 Web App(DOM 节点无限增加导致页面卡死)不同,这两个组件在 App 端直接映射为 Android 的RecyclerView和 iOS 的UICollectionView,具备真正的原生 View 节点回收复用池


一、 传统<scroll-view>vs 原生<list-view>区别

对比项<scroll-view>(传统)<list-view>/<waterfall-view>
底层实现纯滚动容器,把所有节点都加载到内存中原生列表控件,屏幕外节点自动销毁并回收复用
内存开销随数据增加呈线性增长(数千条数据必然卡死/爆内存)内存始终保持在一个常数级(仅保留屏幕可见项 + 缓冲项)
适用场景几条到几十条数据的短页面、局部滚动区域几百到数万条数据的长列表、下拉刷新/上拉加载列表、商城瀑布流

二、<list-view>组件详解

<list-view>用于实现垂直或水平方向的单列/多列普通长列表(如:聊天消息列表、医生列表、问诊历史、处方记录等)。

1. 核心配套组件:<list-item>type机制

list-view的直接子节点必须是<list-item>。 其中最重要的属性是type(复用类型标识)

  • 复用原理:当列表向上滚动时,滑出屏幕顶部的<list-item>节点不会被销毁,而是根据它的type值被放入原生复用池。当底部有新数据要滑入时,系统直接从复用池拿出该节点,仅更新里面的文本和图片数据。
  • 规则
    • 如果列表项的UI 样式完全一致,给它们设置相同的type(如type="0")。
    • 如果列表项有多种不同结构(例如聊天页面:左侧医生消息、右侧患者消息、中间系统提示),必须给不同结构的子项设置不同的type(如type="1"type="2")。
2. 吸顶效果支持 (<sticky-header>)

无需任何 JS 计算滚动高度,在<list-view>中搭配<sticky-header><sticky-section>组件,即可实现纯原生的流畅分组标题吸顶效果。

3. 常见属性与事件
  • scroll-y/scroll-x:开启垂直或水平滚动。
  • refresher-enabled:开启原生下拉刷新。
  • @refresherrefresh:下拉刷新触发事件。
  • @scrolltolower:滚动到底部触发(上拉加载更多)。
  • show-scrollbar:是否显示原生滚动条。
  • bounces:是否开启回弹效果(iOS 原生弹性回弹)。

三、<waterfall-view>瀑布流组件详解

<waterfall-view>专门用于参差不齐高度的卡片瀑布流布局(如:中医健康科普文章瀑布流、中药材/养生产品商城瀑布流)。

1. 解决的痛点

在 Web 时代做瀑布流,通常需要 JS 实时计算左右两列的高度,或者用absolute绝对定位,这会导致频繁触发 Web 重排(Reflow),极为耗性能。<waterfall-view>由 Native 原生 C++ 引擎(AndroidStaggeredGridLayoutManager/ iOSUICollectionViewCompositionalLayout)自动在底层计算卡片高矮,零 JS 布局开销

2. 专属关键属性
  • column-count:瀑布流列数(默认2列)。
  • column-gap:列与列之间的横向间距。
  • row-gap:卡片与卡片之间的纵向间距。
  • custom-header/custom-footer:支持在瀑布流顶部或底部插入跨全宽的 Banner 或加载状态。

四、.uvue实战代码示例

1. 标准<list-view>列表代码示例
<template> <view class="container"> <list-view class="list-container" :scroll-y="true" :refresher-enabled="true" :refresher-triggered="isRefreshing" @refresherrefresh="onRefresh" @scrolltolower="onLoadMore" > <!-- 普通消息项 (type="0") --> <list-item v-for="(item, index) in dataList" :key="item.id" :type="0" class="list-card" > <image class="avatar" :src="item.avatar"></image> <view class="info"> <text class="title">{{ item.name }}</text> <text class="desc">{{ item.diagResult }}</text> </view> </list-item> <!-- 底部加载更多提示 --> <list-item :type="99" class="loading-item"> <text class="loading-text">{{ isLoading ? '加载中...' : '没有更多了' }}</text> </list-item> </list-view> </view> </template> <script setup uts> type DoctorItem = { id: string name: string avatar: string diagResult: string } const dataList = ref<Array<DoctorItem>>([]) const isRefreshing = ref(false) const isLoading = ref(false) const onRefresh = () => { isRefreshing.value = true // 模拟刷新数据 setTimeout(() => { isRefreshing.value = false }, 1000) } const onLoadMore = () => { if (isLoading.value) return isLoading.value = true // 模拟加载下一页 } </script> <style scoped> .container { flex: 1; } .list-container { flex: 1; } .list-card { flex-direction: row; padding: 15px; border-bottom-width: 1px; border-bottom-color: #eee; background-color: #ffffff; } .avatar { width: 50px; height: 50px; border-radius: 25px; } .info { margin-left: 12px; justify-content: center; } .title { font-size: 16px; font-weight: bold; } .desc { font-size: 14px; color: #666; margin-top: 4px; } </style>
2. 瀑布流<waterfall-view>代码示例
<template> <waterfall-view class="waterfall-container" :column-count="2" :column-gap="10" :row-gap="10" @scrolltolower="onLoadMore" > <!-- 瀑布流卡片 (type="1") --> <list-item v-for="article in articleList" :key="article.id" :type="1" class="article-card" > <image class="cover" :src="article.cover" mode="widthFix"></image> <text class="article-title">{{ article.title }}</text> <text class="author">作者:{{ article.author }}</text> </list-item> </waterfall-view> </template>

五、 性能调优三大黄金法则

  1. 必须使用<list-item>包裹并指定type: 千万不要在<list-view>里直接放普通的<view>,否则原生节点无法进行回收复用,就失去了使用list-view的意义。
  2. 不同布局结构的子项必须区分type: 如果子项 A 是带图卡片(type="1"),子项 B 是纯文本标题(type="2"),绝不能将它们的type设为相同,否则复用时会导致 UI 错乱。
  3. 保持子项层级平坦<list-item>内部的节点嵌套层级越浅,原生 View 布局计算速度就越快,滚动流畅度越高。
http://www.cnnetsun.cn/news/4115853.html

相关文章:

  • 收藏夹里 200 个视频,与其一个个手动存,不如看看 douyin-downloader 怎么用一条命令收完
  • SQL优化案例:巧用主键分页减少DISTINCT开销
  • 制造业数据防篡改:从神钢事件看供应链诚信体系建设
  • 电视盒子刷机成Linux服务器的完整实战:amlogic-s9xxx-armbian从零到一
  • 库存管理P系统订货上限计算:从原理到Excel/Python实践
  • 摄像头流媒体太乱?go2rtc 用一个文件解决多协议统一出流
  • paper.json:构建机器可读学术论文,赋能LLM智能体高效科研
  • 从零搭建本地AI服务器:低成本部署大模型与Stable Diffusion实战指南
  • ERP采购订单变更失控:从根源分析到SAP系统实现完整控制方案
  • 全电动飞机试飞技术解析:从5美元电费看能量管理与工程挑战
  • AKConv:自适应卷积核改进目标检测性能的原理与实践
  • 别再被网盘限速折磨!开源网盘直链提取工具从零上手指南
  • Go语言数据结构、算法与设计模式一站式学习指南
  • PhoneHarness:构建混合GUI、CLI与工具的手机智能体统一执行框架
  • N沟道与P沟道MOSFET核心差异详解:从原理到选型避坑指南
  • RDP Wrapper完整实操指南:普通Windows电脑也能多人同时远程登录
  • AI珠宝精修到底是什么?和网上说的AI修图是一回事吗?
  • K7d秒级分叉K8s集群:加速AI训练与GRPO实验的工程实践
  • Qwen3.8-27B本地部署实战:消费级硬件跑通大模型,实测对比云端API
  • 高效能应用
  • 号称厘米级的蓝牙AOA定位,到医院项目就翻车?行业人该清醒了
  • Rhino.Inside.Revit 上手指南:30 分钟让 Rhino 与 Revit 实时联动,告别反复导模型
  • [校大]27届二本巢湖学院JAVA简历:小公司简历通过率仅3%
  • 超简易实时HTML编辑器
  • 手机号查QQ号如何实现?开源 Python 工具 phone2qq 极速速查指南
  • Bun 后端开发中如何实现无反射依赖注入:dunx 库实战指南
  • 抖音批量下载工具douyin-downloader终极指南:30分钟从零到千条视频入库
  • OBS多平台同时推流保姆级教程:obs-multi-rtmp一键搞定多平台直播
  • Linux网络命名空间实战:从零构建虚拟网络拓扑
  • 个人无营业执照如何在抖音、视频号卖课?2026 知识博主合规变现防坑全指南