1. 什么是瀑布流布局
瀑布流布局是一种常见的网页布局方式,也称为流式布局或瀑布式布局。它的特点是将卡片按照一定规则排列,使得页面整体呈现出类似瀑布般的流动感觉,给用户带来直观的视觉冲击。
这种排列方式最早是由Pinterest应用到其网站上的。之后,由于其它社交网站如Twitter、Facebook等的使用,瀑布流布局逐渐成为了一种非常受欢迎的设计风格。
瀑布流布局的特点:
元素按照一定规则排列,形成流式布局。
元素的大小和长宽比不固定,根据内容自适应。
通过JS等方式实现动态加载,让页面更加流畅。
2. 小程序中如何实现瀑布流布局
2.1 瀑布流布局原理
在瀑布流布局中,首先要确定每一列的宽度,然后计算每个元素之间的间隔。在布局的过程中,我们需要记录每一列的高度,以便后续元素的插入。
下面是一个简单的实现瀑布流布局的过程:
// 获取容器的宽度
const width = wx.getSystemInfoSync().windowWidth;
// 每列的宽度
const colWidth = (width - 30) / 2;
// 列数
const colCount = 2;
// 每列的高度
const colHeight = [];
// 遍历卡片,依次插入
cards.forEach((card, index) => {
// 计算元素的宽度和高度
const cardWidth = colWidth;
const cardHeight = (cardWidth / card.aspectRatio) || 200;
// 找到最短的一列,记录其高度
const minHeight = Math.min(...colHeight);
const minIndex = colHeight.indexOf(minHeight);
colHeight[minIndex] += cardHeight;
// 定位元素的位置
const left = minIndex * colWidth + 10 * (minIndex + 1);
const top = minHeight;
card.style = \`width: \${cardWidth}px; height: \${cardHeight}px; left: \${left}px; top: \${top}px;\`;
});
return cards;
以上代码中,我们定义了每列的宽度,然后遍历每个卡片进行插入。在插入前,计算出当前卡片的宽度和高度,然后找到列高度最短的一列,将卡片插入到该列中。
这里重点需要注意的是计算列高度的方式,需要找到最短的一列,并将当前卡片插入到该列中。
2.2 实现瀑布流布局的小技巧
在实现瀑布流布局的过程中,需要注意一些细节问题。
2.2.1 图片加载问题
在瀑布流布局中,图片通常是卡片的主要内容。因此,我们需要在插入卡片前,先加载图片,确保图片的宽高比例正确,避免布局出现问题。
const promiseList = cards.map((card) => {
return new Promise((resolve, reject) => {
wx.getImageInfo({
src: card.image,
success: (res) => {
card.aspectRatio = res.width / res.height;
resolve();
},
fail: reject,
});
});
});
return Promise.all(promiseList).then(() => {
// 布局卡片
}).catch((err) => {
// 图片加载出错
});
以上代码中,我们通过getImageInfo获取图片的宽高比例,然后将所有的promise包裹在Promise.all中,确保所有图片都加载完成后再进行布局,以避免出现计算错误的情况。
2.2.2 动态加载问题
在瀑布流布局中,由于卡片数量较多,因此需要采用动态加载的方式,防止页面卡顿。
一般而言,动态加载有两种方式,一种是在滚动到页面底部时,自动加载更多内容;另一种是在用户交互时,手动触发加载更多内容。
这里推荐采用自动加载的方式,用户体验更加友好。下面是一个简单的实现方式:
$onReachBottom() {
if (this.data.canLoadMore) {
this.loadMore();
}
},
loadMore() {
// 加载更多卡片
}
以上代码中,$onReachBottom方法是小程序提供的页面滚动到底部自动触发的方法。在该方法中,我们判断用户是否允许加载更多内容,如果是,则执行loadMore方法,从服务器获取更多卡片并加入到瀑布流布局中。
3. 总结
瀑布流布局是一种常见的网页布局方式,使页面整体呈现出类似瀑布般的流动感觉,给用户带来直观的视觉冲击。在小程序中,我们可以采用JS等方式实现动态加载,让页面更加流畅。在实现瀑布流布局的过程中,需要注意计算列高度、图片加载、动态加载等一些细节问题。
小程序瀑布流实现的代码示例:
// 瀑布流Layout组件
import { Layout } from '@minui/layout';
Component({
mixins: [Layout],
properties: {
cards: {
type: Array,
default: () => []
}
},
methods: {
async constructItemModel(item, index, onLoad) {
// 等待图片加载完毕
await new Promise(resolve => {
const image = wx.createImage();
image.onload = () => {
item.aspectRatio = image.width / image.height;
onLoad && onLoad();
resolve();
};
image.src = item.image;
});
// 开始布局
const itemWidth = (this.data.width - this.data.gutter * (this.data.columns - 1)) / this.data.columns;
const itemHeight = itemWidth / item.aspectRatio;
const minHeight = Math.min(...this.data.columnsHeight);
const minIndex = this.data.columnsHeight.indexOf(minHeight);
const left = minIndex * (itemWidth + this.data.gutter);
const top = minHeight;
this.setData({
['cards[' + index + '].style']: `width: ${itemWidth}px; height: ${itemHeight}px; left: ${left}px; top: ${top}px;`,
['columnsHeight[' + minIndex + ']']: minHeight + itemHeight + this.data.gutter
});
},
onResize({ width, cardCount }) {
const columns = Math.min(this.data.columns || 3, cardCount);
const columnWidth = (width - (columns - 1) * (this.data.gutter || 0)) / columns;
this.setData({
columns,
width,
columnWidth,
columnsHeight: new Array(columns).fill(0)
});
}
}
});
以上代码使用了minui组件库提供的瀑布流Layout组件,实现了自适应列数、卡片宽度、Gutter、高度等属性,兼容了避免重复调用加载更多方法的问题,提供了数据整体重设接口等。
使用示例:
<ml-layout cards="{{cards}}" loaded="{{loaded}}" total="{{total}}" on-load-more="{{loadMore}}" on-resize="{{onResize}}" gutter="10" columns="2" >
<view slot="card" style="{{card.style}}">
<image src="{{card.image}}" mode="aspectFit" />
</view>
</ml-layout>
其中,ml-layout是瀑布流Layout组件的名称;cards、loaded、total、loadMore、onResize、gutter、columns等都是该组件支持的属性和方法。
上述代码可以供开发者参考使用,同时在实际开发中,需要根据具体需求进行实现和调整。