Implementing a Waterfall Layout with Flex in a Uni‑App
This article explains how to create a two‑column waterfall (masonry) layout in a Uni‑App using Flexbox, covering the visual design, CSS styling, data handling, dynamic loading, height calculation, and tab‑switch integration with complete code examples.
The author introduces a waterfall (masonry) layout, describing its characteristic uneven multi‑column appearance and continuous data loading as the page scrolls.
Using Flexbox, the layout is built with a parent <view class="blessing-con"> that distributes two child containers ( blessing-con-half ) side by side. The HTML structure is:
<view class="blessing-con">
<view class='blessing-con-half'>
<view id="leftHalf">
<view class="blessing-con-half-item" :class="bgColor[index % 3]" v-for="(item, index) in newBlessingWordsList1" :key="index">
<view class="item-con"></view>
</view>
</view>
</view>
<view class='blessing-con-half'>
<view id="rightHalf">
<view class="blessing-con-half-item" :class="bgColor[(index + 1) % 3]" v-for="(item, index) in newBlessingWordsList2" :key="index">
<view class="item-con"></view>
</view>
</view>
</view>
</view>The accompanying CSS defines the flex container and item styles, for example:
.blessing-con {
padding: 32rpx 20rpx;
display: flex;
justify-content: space-between;
height: 1100rpx;
overflow-y: auto;
}
.blessing-con-half {
width: 320rpx;
height: 100%;
}
.blessing-con-half-item {
width: 100%;
display: flex;
flex-direction: column;
margin: 0 0 24rpx;
}Data is stored in two arrays ( newBlessingWordsList1 and newBlessingWordsList2 ) representing the left and right columns. The component fetches items from an API via the asynchronous method getBlessingWall :
async getBlessingWall(type = 0) {
let res = await api.blessingWall({ activityId: this.activityId, pageNum: this.pageWallNum, pageSize: this.pageWallSize });
// process response, update lists, set hasWallNext, etc.
}When more data is needed, handlerMore increments the page number and calls getBlessingWall(1) . A timer started by start() iterates through the fetched list, adding items one by one to the combined list and then distributing them to the shorter column based on current heights:
start() {
clearInterval(this.timer);
this.timer = setInterval(() => {
// add next item to left or right list depending on heights
}, 10);
}The height of each column is obtained with Uni‑App’s selector query in getHei(item) , which compares leftHeight and rightHeight and pushes the item to the appropriate array.
getHei(item) {
const query = uni.createSelectorQuery().in(this);
query.select('#leftHalf').boundingClientRect(res => {
this.leftHeight = res.height;
const query1 = uni.createSelectorQuery().in(this);
query1.select('#rightHalf').boundingClientRect(dataRight => {
this.rightHeight = dataRight.height || 0;
if (this.leftHeight <= this.rightHeight) {
this.newBlessingWordsList1.push(item);
} else {
this.newBlessingWordsList2.push(item);
}
}).exec();
}).exec();
}The component also handles tab switching; only when the second tab is active does it start the height‑balancing timer, ensuring the DOM elements exist before measurement.
In conclusion, the author demonstrates a functional waterfall layout using Flexbox in a Uni‑App, notes that other implementation methods exist, and invites readers to follow for future updates.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.