小程序Taro瀑布流
PS 本例使用Taro和TaroUI
Demo:https://github.com/Noelia1997/waterfall-com-taro
效果:
image-20200622203911231.png
這兩天試了很多種做瀑布流布局的方法,第一種是用flex布局卷员,這種方法只能整齊的排列大小相同的圖片栽烂,不能做到瀑布流的效果介蛉。
image-20200622204437537.png
第二種是根據(jù)序號(hào)的奇偶來(lái)選擇是放在左邊還是右邊,但是如果某列一直放很長(zhǎng)的圖片量承,依舊無(wú)法達(dá)到瀑布流的效果。
image-20200622204537939.png
在網(wǎng)上進(jìn)行了搜索,找到了微信小程序的瀑布流demo裙犹,邏輯有點(diǎn)混亂尽狠,閱讀不夠流暢。
但是通過(guò)閱讀作者的相關(guān)代碼叶圃,知道了兩件事袄膏。
一是:微信小程序<image/>中有一個(gè)屬性bindload,對(duì)應(yīng)在Taro中是onLoad掺冠。
image-20200622204901564.png
注意這個(gè)屬性是在圖片載入完畢時(shí)得到參數(shù)的沉馆!并且最坑的是如果循環(huán)渲染Image的話,如下面:
goodsList.map((item, index) => {
return (
<Image onLoad={this.onImageLoad} id={index} src={item.image}></Image>
)
})
它在循環(huán)結(jié)束以后把所有的圖片根據(jù)圖片的大小排序德崭,小的先執(zhí)行它的bindload斥黑,大的得等等,如果圖片的大小相等接癌,隨機(jī)選擇心赶,無(wú)語(yǔ)。下圖是每次調(diào)用onLoad打印出的id數(shù)據(jù)缺猛,可以看出是隨機(jī)且無(wú)序的缨叫。
image-20200622215902529.png
為了讓每次load圖片時(shí)獲得有序的數(shù)組,我們不對(duì)第一次渲染圖片的組件進(jìn)行操作荔燎。所以在上方的代碼外面包裹一層display:none
<View style={{display: 'none'}}>
{
goodsList.map((item, index) => {
return (
<Image onLoad={this.onImageLoad} id={index} src={item.image}></Image>
)
})
}
</View>
這里的例子里有兩個(gè)列表耻姥,goodsList保存的是初始的數(shù)據(jù),此數(shù)組中無(wú)height有咨,我們要通過(guò)onImageLoad獲得圖片的height琐簇,把獲得height后保存的數(shù)據(jù)放到ImageLoadList中。
onImageLoad = (e) => {
//如果不做計(jì)算這一步座享,圖片在進(jìn)入左列或者右列時(shí)可能會(huì)出現(xiàn)計(jì)算錯(cuò)誤婉商。
let oImgW = e.detail.width; //圖片原始寬度
let oImgH = e.detail.height; //圖片原始高度
let imgWidth = this.state.imgWidth; //圖片設(shè)置的寬度
let scale = imgWidth / oImgW; //比例計(jì)算
let imgHeight = oImgH * scale; //自適應(yīng)高度
//初始化ImageLoadList數(shù)據(jù)
ImageLoadList.push({
id: parseInt(e.currentTarget.id),
height: imgHeight,
})
//載入全部的圖片進(jìn)入ImageLoadList數(shù)組,若數(shù)量和goodsList中相同渣叛,進(jìn)入圖片排序函數(shù)
if (ImageLoadList.length === goodsList.length) {
this.handleImageLoad(ImageLoadList)
}
// console.log(ImageLoadList)
}
二是:制作瀑布流布局需要判斷左右列表的高度
以下是對(duì)ImageLoadList進(jìn)行操作的函數(shù):
handleImageLoad = (ImageLoadList) => {
//對(duì)無(wú)序的列表進(jìn)行冒泡排序
for (let i = 0; i < ImageLoadList.length - 1; i++)
for (let j = 0; j < ImageLoadList.length - i - 1; j++) {
if (ImageLoadList[j].id > ImageLoadList[j + 1].id) {
let temp = ImageLoadList[j]
ImageLoadList[j] = ImageLoadList[j + 1]
ImageLoadList[j + 1] = temp
}
}
//現(xiàn)在的列表在goodList的基礎(chǔ)上丈秩,多了height屬性
console.log('ImageLoadList', ImageLoadList);
//為現(xiàn)在的列表添加value值
for (let i = 0; i < goodsList.length; i++) {
//把原數(shù)組中的屬性賦予ImageLoadList數(shù)組
ImageLoadList[i].value = goodsList[i].value
ImageLoadList[i].image = goodsList[i].image
console.log('ImageLoadList[i].height', ImageLoadList[i].height)
ImageLoadList[i].imgStyle = {height: ImageLoadList[i].height + 'rpx'}
}
console.log('ImageLoadList', ImageLoadList);
//對(duì)現(xiàn)在的列表進(jìn)行操作
let leftHeight = 0; //左邊列表的高度
let rightHeight = 0;
let left = [] //左邊列表的數(shù)組
let right = []
//遍歷數(shù)組
for (let i = 0; i < ImageLoadList.length; i++) {
console.log('左邊的高度', leftHeight, '右邊邊的高度', rightHeight)
if (leftHeight <= rightHeight) {
console.log('第', i + 1, '張放左邊了')
left.push(ImageLoadList[i])
leftHeight += ImageLoadList[i].height
console.log('left', left);
} else {
console.log('第', i + 1, '張放右邊了')
right.push(ImageLoadList[i])
rightHeight += ImageLoadList[i].height
console.log('right', right);
}
}
this.setState({
goodsRight: right,
goodsLeft: left
}, () => {
console.log(this.state);
})
}
另外使用React框架的push有一個(gè)坑,我們不能對(duì)state進(jìn)行push淳衙,例如
this.state.goodsRight.push(imgObj) //× 錯(cuò)誤寫法
//正確寫法
let array = []
array.push(imgObj)
this.setState({
goodsRight : array
})
render()
<ScrollView>
{
<View className={'goods-left'}>
{
goodsLeft.map((item, index) => {
return (
<View className={'goods-item'}>
<Image src={item.image} className={'goods-img'} style={item.imgStyle} id={index}
mode='widthFix'/>
<View className={'goods-name'}>{item.value}</View>
</View>
)
})
}
</View>
}
</ScrollView>
<ScrollView>
{
<View className={'goods-right'}>
{
goodsRight.map((item, index) => {
return (
<View className={'goods-item'}>
<Image src={item.image} className={'goods-img'} style={item.imgStyle} id={index}
mode='widthFix'/>
<View className={'goods-name'}>{item.value}</View>
</View>
)
})
}
</View>
}
</ScrollView>