您好,登錄后才能下訂單哦!
小編給大家分享一下小程序多圖列表怎么實現性能優化,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
什么造成的性能問題
簡單的來說: DOM節點過多 && 圖片節點過多
DOM節點過多會造成更多的內存占用. 按照目前的微信小程序限制, 內存占用500M以上會出現卡頓, 甚至閃退. 如果列表中節點沒有圖片標簽, 內存占用現象還不會太明顯, 只是DOM節點過多會造成頁面渲染耗時增加. 但當列表節點中含有圖片時, 內存占用會迅速攀升.
如何解決這兩點呢?
對于上面兩點, 我們分別有對應的優化思路
1. DOM節點過多.
對于無限加載的頁面, 列表中每一個元素都有大量的子節點. 當列表數目增加時, 頁面的總節點數會暴增. 以小紅書的小程序為例:
上圖中可以看到, 該頁面為很多的卡片組成的列表頁面. 假設一個卡片的DOM子節點數為 30, 那么當列表元素加載到1000時, 頁面會有 30 * 1000 = 30,000
個DOM節點. 小程序顯然是吃不消的 (注: 微信小程序推薦總節點數不超過: 1000)
那我們該如何處理來減少節點數呢?
思路很簡單: 我們可以只對用戶當前屏幕和上下兩屏進行真實內容的加載, 對于其他用戶暫時不可見的地方, 用空白的節點進行占位. 這樣處理后, 實際有內容的卡片數目不超過5個, 頁面的總節點數為: 5 * 30 + 995 = 1145
. 相對于之前的節點數有了巨大的改進.
讓我們來看看代碼的實現
寫代碼前, 讓我們整理一下需要的數據結構.
首先這是一個列表頁面, 我們需要一個 List來保存頁面顯示的數據: showCards
. showCards
中只會保存5條真實數據, 其余數據展示以空對象填充.
我們還需要一個保存所有真實數據的List, 這樣當用戶滑動頁面時, 我們才能實時獲取需要顯示的卡片真實數據: totalCards
Page({ showCards: [], totalCards: [] })
接下來我們來寫頁面布局部分:
<view wx:for="{{showCards}}" wx:key="{{index}}"> <self-define-component data-card-data="{{item}}"> </self-define-component> </view>
簡單的代碼框架就是這樣 (這里省略了很多不影響理解思路的代碼細節)
我們先實現沒有優化DOM節點的代碼邏輯. 在頁面滑動到最底部時, 向showCards
push進新的卡片, 并通過 setData
更新頁面. 這樣就實現了一個簡單的下拉無限加載的列表頁面.
async onReachBottom() { const newCards = await fetchNewCards(); this.data.showCards.push(newCards); this.setData({ showCards: this.data.showCards }) },
接下來我們實現優化DOM節點的代碼邏輯. 我們會再用戶滑動頁面(onScroll
事件) 時, 對當前頁面每個card
的位置進行判斷, 如果該 card在用戶可見范圍內的上下兩屏內, 則展示真實數據, 否則將其替換為寬高與原卡片一致的空白占位節點.
在 Page 的 onPageScroll
回調中, 我們進行回收函數的調用 (注意這里回調時要進行節流處理, 否則頻繁調用會導致頁面閃動) . 讓我們看看這個回收頁面節點函數的主要邏輯:
回調中, 我們首先通過小程序提供的獲取頁面元素位置的api: createSelectorQuery().boundingClientRect
來拿到每個卡片的位置信息.
接下來, 我們通過位置信息, 判斷是否展示card的真實數據. 對于不展示真實數據的card, 我們需要保存其高度信息, 以便在渲染頁面時使用高度信息填充頁面. 同時我們給空card一個 type 屬性, 方便我們在 wxml中渲染時判斷卡片類型.
async onScrollCallback() { try { const rectList = await this.calcCardsHeight(); this.recycleCard(rectList); } catch (e) { console.error(e); } } calcFeedHeight() { return new Promise((resolve, reject) => { this.createSelectorQuery() .selectAll(`.card`) .boundingClientRect(rectList => { resolve(rectList); }) .exec() }) }, recycleCard(rectList) { const newShowCards = []; for (let i = 0; i < this.data.showCards.length; i++) { const rect = rectList[i]; if (rect && Math.abs(rectList[i].top - 0) > pageHeight * 2) { newShowCards.push({ type: 'empty-card', height: rectList[i].bottom - rectList[i].top }); } else { const feed = totalCards[i]; newShowCards.push(feed); } } this.setData({ showCards: newShowCards }); }
接下來, 我們要對wxml布局文件進行相應的修改:
<view wx:for="{{showCards}}" wx:key="{{index}}"> <view wx:if="{{item.type === 'empty-card'}}" class="card empty-card" > </view> <self-define-component wx:if="{{item.type !== 'empty-card'}}" data-card-data="{{item}}" class="card read-card"> </self-define-component> </view>
這樣, 我們就解決了 DOM節點數目過多的問題. 并且最大限度的不影響用戶的體驗. (雖然用戶快速上下滑動時還是會看到一些空白, 但大多數情況用戶不會非常快速的上下滑, 而是閱讀內容并慢速滑動)
2. 圖片節點過多
通過上面一步的優化, 我們其實已經大幅減少了頁面加載的圖片數目. 但是有些情況, 我們的列表中的每一個卡片并不是只有一張圖, 有時我們的圖片組件是一個 swiper. 我們假設每個swiper平均展示10張圖片, 那么我們展示5張card的話,<Image/>
節點就有 50 個. 對于一些低端的安卓機, 這樣的開銷依然會造成卡頓.
那有什么好的優化方案呢? 前面一個問題, 我們的優化思路是在用戶看不見的地方, 將節點簡化展示.
同樣的, 對于swiper控件, 用戶能看到的也就是當前圖片 以及 滑動可見的左右兩張圖片. 其余位置的圖片是可以簡化展示的. 從下圖可以看到, 其實需要立即加載的圖片只有三張. (紅色的框代表的是swiper組件的可視區域)
我們使用一個變量記錄當前swiper控件展示圖片的坐標: curIndex
, 然后我們改造一下 wxml布局文件. 代碼邏輯很簡單, 就是通過判斷當前Image 節點的index和swiper展示節點的 index之間距離, 大于2就不顯示.
經過這樣的處理后, 我們的每個swiper組件, 最多只會有三個占用實際內存的 <Image/>
節點.
<swiper-item wx:for="{{images}}" wx:key="{{index}}"> <view > <image class="img" mode="widthFix" src="{{index - curIndex < 2 && index - curIndex > -2 ? item.url : ''}}"> </image> </view> </swiper-item>
以上是“小程序多圖列表怎么實現性能優化”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。