小程序瀑布流組件實(shí)現(xiàn)翻頁(yè)與圖片懶加載
電商小程序中,用到瀑布流的地方非常多,每次都寫一個(gè)瀑布流,重復(fù)一次邏輯,作為程序員,肯定是非常不愿意的。
瀑布流的形式都是大同小異,不同的是瀑布流中每個(gè)模塊的內(nèi)容,隨業(yè)務(wù)而變化。
所以,我們把瀑布流框架抽象成組件,瀑布流的內(nèi)容由業(yè)務(wù)確定。這樣即可實(shí)現(xiàn)組件化和自定義的最大平衡,微信小程序組件源碼。
首先,我們來(lái)看一下瀑布流組件在實(shí)際項(xiàng)目中的實(shí)際效果。
1 實(shí)際效果
瀑布流組件實(shí)際效果如下圖所示,左側(cè)為用戶交互效果,右側(cè)為圖片懶加載實(shí)際效果。

2 什么是瀑布流?
瀑布流,又稱瀑布流式布局。是比較流行的一種網(wǎng)站頁(yè)面布局,waterfall-item寬度固定,高度不定,視覺(jué)表現(xiàn)為參差不齊的多欄布局,隨著頁(yè)面滾動(dòng)條向下滾動(dòng),這種布局還會(huì)不斷加載數(shù)據(jù)塊并附加至當(dāng)前尾部。如下圖所示:

3 實(shí)現(xiàn)功能
該瀑布流組件實(shí)現(xiàn)了以下幾個(gè)功能:
- 支持圖片懶加載
- 支持上拉數(shù)據(jù)翻頁(yè)
- 支持自定義樣式
- 支持瀑布流Item間隔底層自動(dòng)計(jì)算
- 原生組件模式:即類swiper和swiper-item 組件用法
- 組件與數(shù)據(jù)完全解耦
4 實(shí)現(xiàn)原理
4.1 waterfall 和waterfall-item實(shí)現(xiàn)原理
第一步:在 waterfall-layout 目錄下創(chuàng)建 waterfall 和 waterfall-item 組件,目錄結(jié)構(gòu)如下:
. ├── query-node.js ├── waterfall-item.js ├── waterfall-item.json ├── waterfall-item.wxml ├── waterfall-item.wxss ├── waterfall.js ├── waterfall.json ├── waterfall.wxml └── waterfall.wxss
第二步:分別在waterfall.js 和 waterfall-item.js的relations選項(xiàng)中指定組件父、子級(jí)關(guān)系:
// waterfall.js
Component({
// ... other code
relations: {
'./waterfall-item': {
type: 'child',
},
// ... other code
}
})
// waterfall-item.js
Component({
// ... other code
relations: {
'././waterfall': {
type: 'parent',
},
// ... other code
}
})
指定彼此的父、子組件的關(guān)系后,即可通過(guò) this.getRelationNodes 原生 API,就能訪問(wèn)彼此實(shí)例對(duì)象及其屬性和方法。
第三步:實(shí)現(xiàn)waterfall.wxml 和 waterfall-item.wxml代碼:
waterfall.wxml代碼實(shí)現(xiàn)非常簡(jiǎn)單,只有5行代碼:
<view class="waterfall custom-class"> <view class="waterfall-inner"> <slot ></slot> </view> </view>
同樣,waterfall-item.wxml代碼實(shí)現(xiàn)也非常簡(jiǎn)單,只有5行代碼:
<view
class="waterfall-item custom-class"
style="{{position}}:0;top:{{(top >= 0 ? top + 'px' : 0 + 'rpx')}};"
>
<slot ></slot>
</view>
不知道slot用法的童鞋,請(qǐng)參考微信小程序自定義組件模板和樣式文檔。
4.2 瀑布流原理
其實(shí),不管是微信小程序、web、還是原生APP,瀑布流的實(shí)現(xiàn)原理都是一樣的。都可以絕對(duì)定位和位置計(jì)算來(lái)實(shí)現(xiàn)。
瀑布流的大體過(guò)程如下圖所示:
第一步:數(shù)據(jù)通過(guò)this.setData從邏輯層傳輸?shù)揭晥D層,進(jìn)行第一渲染,由于每個(gè)waterfall-item 的top:0; 和 position:left;,所以都重疊了在一起。
第二步:通過(guò)節(jié)點(diǎn)查詢API獲取每個(gè)waterfall-item元素信息,并且計(jì)算出正確的top和position值。
第三步:setData每個(gè)waterfall-item的top和position,實(shí)現(xiàn)重排。

具體邏輯實(shí)現(xiàn)如下:
首先,我們來(lái)實(shí)現(xiàn)一個(gè)節(jié)點(diǎn)查詢API querySelector,之后會(huì)用到:
// query-node.js
/**
* 獲取當(dāng)前頁(yè)面中,選擇器為 selector 的第一個(gè)node節(jié)點(diǎn)
* @param {String} selector 符合微信小程序規(guī)范的選擇器
* @param {Object} context 調(diào)用環(huán)境,普通頁(yè)面中為wx,自定義組件中為this;默認(rèn)值為wx.
* @return {Array} 返回一個(gè)數(shù)組,第一個(gè)元素為 node 節(jié)點(diǎn)
*/
export const querySelector = function (selector, context = wx) {
return new Promise((resolve, reject) => {
context.createSelectorQuery()
.select(selector)
.boundingClientRect((res) => {
if (res) {
resolve(res);
} else {
reject(`不存在選擇器為 ${selector} 的節(jié)點(diǎn)`);
}
})
.exec();
})
};
接著,看一下組件waterfall 和waterfall-item在實(shí)際項(xiàng)目中的用法:
<waterfall
loading="{{loadMorePending}}"
isAllLoaded="{{isAllLoaded}}"
>
<block wx:for="{{data.sections}}" wx:key="id" wx:for-item="product">
<waterfall-item
index="{{index}}"
custom-class="flow-item-wrapper"
>
<view class="product-item">
業(yè)務(wù)代碼
</view>
</waterfall-item>
</block>
</waterfall>
當(dāng)?shù)谝粋€(gè)waterfall-item組件,在視圖層布局完成后會(huì)執(zhí)行ready生命周期鉤子。
在 ready 生命周期鉤子中,我們需要做兩件事:
- 獲取父組件
waterfall的實(shí)例對(duì)象,并掛載在waterfall-item組件的this實(shí)例對(duì)象上。因?yàn)橹笪覀冃枰?code>waterfall-item組件中修改waterfall上的數(shù)據(jù)。 - 獲取
waterfall-item組件的高度,計(jì)算waterfall-item組件的位置信息top和position。
// waterfall-item.js
import { querySelector } from './query-node';
Component({
// ... other code
lifetimes: {
ready() {
const [waterfall] = this.getRelationNodes('./waterfall');
this.parent = waterfall;
this.setWaterfallItemPosition();
},
}
methods:{
async setWaterfallItemPosition() {
querySelector('.waterfall-item', this)
.then(async (node) => {
const { top, position } = await this.parent.getWaterfallItemPostionInfo(node);
this.setData({
top,
position
})
})
},
}
// ... other code
})
在setWaterfallItemPosition方法中,我們調(diào)用了父組件上的方法this.parent.getWaterfallItemPostionInfo,獲取當(dāng)前waterfall-item組件的top和position信息。并把已經(jīng)渲染好的waterfall-item組件的累計(jì)高度緩存在waterfall的leftHeights和rightHeights屬性上,用于計(jì)算下一個(gè)waterfall-item組件位置,主要邏輯如下:
// waterfall.js
const POSITION_LEFT = 'left';
const POSITION_RIGHT = 'right';
Component({
// ... other code
/**
* 組件的方法列表
*/
methods: {
lifetimes: {
ready() {
this.initParams();
}
},
initParams() {
this.leftHeights = 0;
this.rightHeights = 0;
},
/**
* 設(shè)置 waterfall-item 的高度值
* @param {Object} node waterfall-item 組件位置尺寸數(shù)據(jù)
*/
async getWaterfallItemPostionInfo(node) {
let top = 0;
let position = POSITION_LEFT;
const { height } = node;
const { itemGap } = this;
if (this.leftHeights <= this.rightHeights) {
top = this.leftHeights;
if(this.leftHeights === 0) {
this.leftHeights += height;
} else {
top += itemGap;
this.leftHeights += (height + itemGap);
}
} else {
position = POSITION_RIGHT;
top = this.rightHeights;
if(this.rightHeights === 0) {
this.rightHeights += height;
} else {
top += itemGap;
this.rightHeights += (height + itemGap);
}
}
return {
top,
position,
}
}
// ... other code
}
})
當(dāng)所有的waterfall-item重排結(jié)束后,瀑布流渲染完成。
4.3 圖片懶加載原理
微信小程序中,<image>標(biāo)簽本身是支持懶加載的,當(dāng)lazy-load={{true}},且在即將進(jìn)入一定范圍(上下三屏)時(shí)才開(kāi)始加載。
也就是說(shuō),當(dāng)lazy-load={{true}},<image>標(biāo)簽初次渲染在視口上下三屏之外時(shí),是不會(huì)請(qǐng)求圖片資源的,當(dāng)<image>即將進(jìn)入三屏之內(nèi)時(shí),才會(huì)加載。
在4.2小節(jié)的圖3中,<waterfall-item>的初始化位置設(shè)置成了top:0; 和 position:left;,所以,都在視口中。如果將top的值成三屏之外的數(shù)值,例如,400vh或者更大,則<waterfall-item>重排之后,任然在三屏之外的圖片即會(huì)自動(dòng)懶加載。
<view
class="waterfall-item custom-class"
style="{{position}}:0;top:{{(top >= 0 ? top + 'px' : itemCount * 100 + 'vh')}};"
>
<slot ></slot>
</view>
Component({
// waterfall-item.js
// ... other code
lifetimes: {
ready() {
const { itemCount } = this.data;
const [waterfall] = this.getRelationNodes('./waterfall');
waterfall.childCount += 1;
this.parent = waterfall;
this.setData({
itemCount: itemCount + waterfall.childCount,
})
},
},
// ... other code
})
4.4 數(shù)據(jù)翻頁(yè)
因?yàn)閷?shí)現(xiàn)了wx:for <waterfall-item>功能,和<swiper-item>組件一樣,因此翻頁(yè)邏輯完全由用戶自己定制,<waterfall>和<waterfall-item>只給你提供翻頁(yè)的功能,組件就可以和瀑布流數(shù)據(jù)結(jié)構(gòu)完全解耦。
4.5 瀑布流Item間隔底層自動(dòng)計(jì)算
將列和行中,兩個(gè)<waterfall-item>組件之間的距離定義為itemGap,則:
itemGap = waterfall寬度 - (waterfall-item寬度 * 2)
在<waterfall> 的ready鉤子中,可以獲取到<waterfall>組件的寬度;同理,在<waterfall-item>的ready鉤子中,可以獲取到<waterfall-item>組件的寬度。
在調(diào)用getWaterfallItemPostionInfo之前,獲取到itemGap的值即可。這樣,在計(jì)算<waterfall-item>的top值時(shí),除了第一行的<waterfall-item>的top值等于0之外,其他所有<waterfall-item>的top值等于:
// this.leftHeights += height + itemGap; // or // this.rightHeights += height + itemGap;
具體代碼實(shí)現(xiàn)請(qǐng)查看源碼
5 總結(jié)
通過(guò)瀑布流框架抽象,使<waterfall>和<waterfall-item>接近原生組件使用體驗(yàn),同時(shí)使組件與數(shù)據(jù)完全解耦。通過(guò)巧妙的初始化位置top設(shè)置,使瀑布流具圖片有懶加載的功能。
到此這篇關(guān)于小程序瀑布流組件實(shí)現(xiàn)翻頁(yè)與圖片懶加載的文章就介紹到這了,更多相關(guān)小程序瀑布流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS獲取隨機(jī)數(shù)函數(shù)可自定義最小值最大值
這篇文章主要介紹的是一個(gè)JS獲取隨機(jī)數(shù)的函數(shù)可自定義最小值最大值,需要的朋友可以參考下2014-05-05
JS+JQuery實(shí)現(xiàn)無(wú)縫連接輪播圖
這篇文章主要介紹了JS+JQuery實(shí)現(xiàn)無(wú)縫連接輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
Cpage.js給組件綁定事件的實(shí)現(xiàn)代碼
Cpage.js是一款輕量級(jí)的Mvvm框架,使用TypeScript(JavaScript的超集)開(kāi)發(fā)。下面通過(guò)本文給大家分享Cpage.js給組件綁定事件的實(shí)現(xiàn)代碼,需要的的朋友參考下吧2017-08-08
js調(diào)用打印機(jī)打印網(wǎng)頁(yè)字體總是縮小一號(hào)的解決方法
直接調(diào)用window.print(),但是打印出來(lái)后,字體總是縮小一號(hào),后來(lái)直接target="_blank",就可以正常打印了,下面是實(shí)現(xiàn)代碼2014-01-01
JavaScript事件流之事件處理和傳播機(jī)制深入理解
本文將詳細(xì)介紹JavaScript事件流的發(fā)展流程、屬性以及應(yīng)用場(chǎng)景,并提供一些代碼示例和引用資料,幫助讀者深入理解并應(yīng)用這一重要的前端技術(shù),希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
打印Proxy對(duì)象和ref對(duì)象的包實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了打印Proxy對(duì)象和ref對(duì)象的包實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
javascript中new Array()和var arr=[]用法區(qū)別
給大家分析一下在javascript中數(shù)組函數(shù)new Array()和var arr=[]用法區(qū)別,一起跟著學(xué)習(xí)一下吧。2017-12-12
JS中toFixed()方法四舍五入的精度問(wèn)題詳解
最近在做項(xiàng)目的時(shí)候,遇到了有四舍五入保留兩位的需求,當(dāng)時(shí)不假思索的直接使用了js原生的toFixed方法,結(jié)果出現(xiàn)了問(wèn)題,這篇文章主要給大家介紹了關(guān)于JS中toFixed()方法四舍五入精度問(wèn)題的相關(guān)資料,需要的朋友可以參考下2021-10-10
微信小程序?qū)W習(xí)筆記之跳轉(zhuǎn)頁(yè)面、傳遞參數(shù)獲得數(shù)據(jù)操作圖文詳解
這篇文章主要介紹了微信小程序?qū)W習(xí)筆記之跳轉(zhuǎn)頁(yè)面、傳遞參數(shù)獲得數(shù)據(jù)操作,結(jié)合實(shí)例形式分析了微信小程序基于navigator組件的頁(yè)面跳轉(zhuǎn)及數(shù)據(jù)傳遞相關(guān)操作技巧,并結(jié)合圖文形式進(jìn)行詳細(xì)說(shuō)明,需要的朋友可以參考下2019-03-03

