鴻蒙OSUniApp 制作動態加載的瀑布流布局#三方框架 #Uniapp

使用 UniApp 制作動態加載的瀑布流布局

前言

最近在開發一個小程序項目時,遇到了需要實現瀑布流布局的需求。眾所周知,瀑布流布局在展示不規則尺寸內容(如圖片、商品卡片等)時非常美觀和實用。但在實際開發過程中,我發現普通的 flex 或 grid 布局很難滿足這一需求,尤其是當需要配合上拉加載更多功能時,更是增加了實現難度。

經過一番摸索和實踐,我總結出了一套在 UniApp 中實現動態加載瀑布流布局的方案,希望能給大家提供一些參考和幫助。

瀑布流布局原理

瀑布流布局的核心思想是:將元素按照自上而下的方式依次排列,但不是簡單地一列一列排,而是始終將新元素放置在當前高度最小的那一列,這樣就能保證各列高度盡可能接近,整體視覺效果更加協調。

技術實現思路

在 UniApp 中實現瀑布流布局,我嘗試過以下幾種方案:

  1. 使用原生 CSS 的 column 屬性
  2. 使用 flex 布局模擬
  3. 使用 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. 性能優化

在數據量很大時,可能會出現性能問題。我的解決方案是:

  1. 使用虛擬列表,只渲染可見區域的元素
  2. 分批次添加數據,而不是一次性添加所有數據
  3. 對于復雜計算,使用防抖和節流技術
// 分批次添加數據
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中實現動態加載的瀑布流布局,我們可以為用戶提供更好的視覺體驗和瀏覽效率。這種布局特別適合展示不規則尺寸的內容,如圖片、商品卡片等。

實現這種布局的關鍵在于:

  1. 正確計算每列的高度并動態分配新元素
  2. 處理好圖片加載和元素高度計算的問題
  3. 結合動態加載實現無限滾動效果
  4. 針對性能問題進行優化

希望這篇文章對你在UniApp中實現瀑布流布局有所幫助。如果有任何問題或建議,歡迎在評論區交流討論!

參考資料

  1. UniApp官方文檔:https://uniapp.dcloud.io/
  2. 瀑布流布局原理:https://www.w3cplus.com/css/pure-css-create-masonry-layout.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/905758.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/905758.shtml
英文地址,請注明出處:http://en.pswp.cn/news/905758.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ThinkStation圖形工作站進入BIOS方法

首先視頻線需要接在獨立顯卡上&#xff0c;重新開機&#xff0c;持續按F1&#xff0c;或者顯示器出來lenovo的logo的時候按F1&#xff0c;這樣就進到bios里了。聯*想*坑&#xff0c;戴爾貴。靠。

【源碼級開發】Qwen3接入MCP,企業級智能體開發實戰!

Qwen3接入MCP智能體開發實戰&#xff08;上&#xff09; 一、MCP技術與Qwen3原生MCP能力介紹 1.智能體開發核心技術—MCP 1.1 Function calling技術回顧 如何快速開發一款智能體應用&#xff0c;最關鍵的技術難點就在于如何讓大模型高效穩定的接入一些外部工具。而在MCP技術…

Linux下載與安裝

一、YUM 1.1 什么是YUM 在CentOS系統中&#xff0c;軟件管理方式通常有三種方式&#xff1a;rpm安裝、yum安裝以及編譯&#xff08;源碼&#xff09;安裝。 編譯安裝&#xff0c;從過程上來講比較麻煩&#xff0c;包需要用戶自行下載&#xff0c;下載的是源碼包&#xff0c;需…

PostgreSQL中的全頁寫

一、概述 在PGSQL數據庫中&#xff0c;默認的頁面大小為8KB&#xff0c;但是磁盤buffer的大小為4KB&#xff0c;扇區大小為512B。這就導致在操作系統的角度看數據庫的寫操作&#xff0c;其實并不是一種原子操作。如果操作系統發生了系統級別的故障&#xff0c;此時正好操作系統…

WEB安全--Java安全--shiro550反序列化漏洞

一、前言 什么是shiro&#xff1f; shiro是一個Apache的Java安全框架 它的作用是什么&#xff1f; Apache Shiro 是一個強大且靈活的 Java 安全框架&#xff0c;用于處理身份驗證、授權、密碼管理以及會話管理等功能 二、shiro550反序列化原理 1、用戶首次登錄并勾選記住密碼…

2024 睿抗機器人開發者大賽CAIP-編程技能賽-專科組(國賽)解題報告 | 珂學家

前言 題解 2024 睿抗機器人開發者大賽CAIP-編程技能賽-專科組&#xff08;國賽&#xff09;&#xff0c;陳越姐姐出題。 國賽比省賽&#xff0c;難度增強了不少&#xff0c;題目就剩下4個題了。 涉及堆棧&#xff0c;hash表&#xff0c;優先隊列等高階數據結構的使用&#x…

15 C 語言字符類型詳解:轉義字符、格式化輸出、字符類型本質、ASCII 碼編程實戰、最值宏匯總

1 字符類型概述 在 C 語言中&#xff0c;字符類型 char 用于表示單個字符&#xff0c;例如一個數字、一個字母或一個符號。 char 類型的字面量是用單引號括起來的單個字符&#xff0c;例如 A、5 或 #。 當需要表示多個字符組成的序列時&#xff0c;就涉及到了字符串。在 C 語言…

操作系統-鎖/內存/中斷/IO

文章目錄 鎖自旋鎖互斥鎖悲觀鎖和樂觀鎖 內存管理物理/虛擬內存頁表段表虛擬內存布局寫時復制copy on writebrk&#xff0c;mmap頁面置換算法 中斷中斷分類中斷流程 網絡I/OI/O模型服務器處理并發請求 鎖 自旋鎖 自旋鎖是一種基于忙等待&#xff08;Busy-Waiting&#xff09;…

割點與其例題

割點 定義&#xff1a; 若一個點在圖中被去掉后&#xff0c;圖的連通塊個數增加&#xff0c;那么這個點就被稱為“割點”。如下圖所示紅點。 定義說白了就是若去掉一個點&#xff0c;圖被“斷開”的點稱為割點。 樸素算法&#xff1a; 枚舉每個點 u。遍歷圖&#xff0c;如果…

圖卷積神經網絡(Graph Convolutional Network, GCN)

最近看論文看到了圖卷積神經網絡的內容&#xff0c;之前整理過圖神經網絡的內容&#xff0c;這里再補充一下&#xff0c;方便以后查閱。 圖卷積神經網絡&#xff08;Graph Convolutional Network, GCN&#xff09; 圖卷積神經網絡1. 什么是圖卷積神經網絡&#xff08;GCN&#…

安裝win11硬盤分區MBR還是GPT_裝win11系統分區及安裝教程

最近有網友問我,裝win11系統分區有什么要求裝win11系統硬盤分區用mbr還是GPT&#xff1f;我們知道現在的引導模式有uefi和legacy兩種引導模式&#xff0c;如果采用的是uefi引導模式&#xff0c;分區類型對應的就是gpt分區(guid)&#xff0c;如果引導模式采用的是legacy&#xf…

服務培訓QDA 的安裝調試方法,硬件模塊的講解和軟件控制臺使用及系統測試

#服務培訓##質譜儀##軟件控制##硬件模塊# 以下是關于Waters QDa單桿液質質譜儀的安裝調試、硬件模塊講解以及軟件控制臺使用培訓的相關內容&#xff1a; 安裝調試 場地準備&#xff1a;用戶需要提前準備好實驗室&#xff0c;確保實驗室環境符合儀器的要求&#xff0c;如溫度、…

在K8S集群中部署EFK日志收集

目錄 引言環境準備安裝自定義資源部署ElasticsearchMaster 節點與 Data 節點的區別生產優化建議安裝好以后測試ES是否正常部署Fluentd測試filebeat是否正常推送日志部署Kibana獲取賬號密碼&#xff0c;賬號是&#xff1a;elastic集群測試 引言 系統版本為 Centos7.9內核版本為…

polarctf-web-[rce1]

考點&#xff1a; (1)RCE(exec函數) (2)空格繞過 (3)執行函數(exec函數) (4)閉合(ping命令閉合) 題目來源&#xff1a;Polarctf-web-[rce1] 解題&#xff1a; 這段代碼實現了一個簡單的 Ping 測試工具&#xff0c;用戶可以通過表單提交一個 IP 地址&#xff0c;服務器會執…

【串流VR手勢】Pico 4 Ultra Enterprise 在 SteamVR 企業串流中無法識別手勢的問題排查與解決過程(Pico4UE串流手勢問題)

寫在前面的話 此前&#xff08;用Pico 4U&#xff09;接入了MRTK3&#xff0c;現項目落地需要部署&#xff0c;發現串流場景中&#xff0c;Pico4UE的企業串流無法正常識別手勢。&#xff08;一體機方式部署使用無問題&#xff09; 花了半小時解決&#xff0c;怕忘&#xff0c;…

ES(Elasticsearch)的應用與代碼示例

Elasticsearch應用與代碼示例技術文章大綱 一、引言 Elasticsearch在現代化應用中的核心作用典型應用場景分析&#xff08;日志分析/全文檢索/數據聚合&#xff09; 二、環境準備(前提條件) Elasticsearch 8.x集群部署要點IK中文分詞插件配置指南Ingest Attachment插件安裝…

臨床決策支持系統的提示工程優化路徑深度解析

引言 隨著人工智能技術在醫療領域的迅猛發展,臨床決策支持系統(CDSS)正經歷從傳統規則引擎向智能提示工程的范式轉變。在這一背景下,如何構建既符合循證醫學原則又能適應個體化醫療需求的CDSS成為醫學人工智能領域的核心挑戰。本報告深入剖析了臨床決策支持系統中提示工程的…

火山RTC 8 SDK集成進項目中

一、SDK 集成預備工作 1、SDK下載 https://www.volcengine.com/docs/6348/75707 2、解壓后 3、放在自己項目中的位置 1&#xff09;、include 2&#xff09;、lib 3)、dll 暫時&#xff0c;只需要VolcEngineRTC.dll RTCFFmpeg.dll openh264-4.dll&#xff0c; 放在intLive2…

OkHttp用法-Java調用http服務

特點&#xff1a;高性能&#xff0c;支持異步請求&#xff0c;連接池優化 官方文檔&#xff1a;提供快速入門指南和高級功能&#xff08;如攔截器、連接池&#xff09;的詳細說明&#xff0c;GitHub倉庫包含豐富示例。 社區資源&#xff1a;中文教程豐富&#xff0c;GitHub高…

python中常用的參數以及命名規范

以下是 Python 中常見的命名規范、參數用法及在大型項目中常用的操作模式&#xff0c;供記錄參考&#xff1a; 1. 命名規范&#xff08;Naming Conventions&#xff09; 前綴/形式含義示例_age單下劃線&#xff1a;弱“私有”標記&#xff08;可訪問但不建議外部使用&#xff…