小程序实现瀑布流布局

1,819 阅读3分钟

1 瀑布流是什么?

瀑布流布局是比较流行的一种网站页面布局,有一个专业的英文名称 Masonry Layouts。

瀑布流布局已经有好多年的历史了,其中最典型的例子是:Pinterest网站。

瀑布流布局其核心是基于一个网格的布局,由宽度相等高度不定的元素组成的参差不齐的多栏布局,随着页面的向下滚动,新的元素自动附加到最短的一列,以此不断的加载。


2 瀑布流实现原理:

当有新的元素需要展示时,每次都是寻找各列之中高度最小的一列,并将新的元素添加到该列后面。

3 代码实现:

最终时间的效果为:


3.1 确定每一列的宽度

在小程序中,引入了尺寸单位:rpx(responsive pixel),可以根据屏幕宽度进行自适应。转换规则如下:


而后端返回的图片的宽度和高度的单位一般都是px,如何正确的转化,才能计算出正确的缩放比例以及缩放后的图片尺寸?

(1)统一计算单位。

(2)计算每一列的宽度waterfallWidth。


假设设置每一列的宽度为 328rpx,原始图片的宽为picWidth,高为picHeight。

首页把宽度转为px可得每一列的宽度:

waterfallWidth= 328 * (Math.floor((wx.getSystemInfoSync().windowWidth / 750) * 100) / 100) px


3.2 计算最终图片展示时的高度

根据图片最终展示的宽度为 waterfallWidth,动态计算每张图片对应的高度:

(1)首先计算缩放比例:

scale = waterfallWidth / picWidth;
(2)缩放后的图片高度:

afterPicHeight = picHeight * scale;

3.3 计算会影响列高度的其他元素高度

要正确的寻找最短的那一列,除了图片,图片上下区域如果非固定的,可变动的,会影响列高度的元素都需要列入考虑。

此处,需要额外考虑的是图片描述区域的高度。

(1)计算图片描述区域行数:

/**
 * 参数说明:
 * text:计算的文本
 * num:一行的字节数
 * return:一行一行组成的数组
 */
textByteLength(text, num) {
  let strLength = 0;
  let rows = 1;
  let str = 0;
  const textArr = [];
  for (let i = 0; i < text.length; i++) {
    if (text.charCodeAt(i) > 255) {
      strLength += 2;
      if (strLength > rows * num) {
        strLength++;
        textArr.push(text.slice(str, i));
        str = i;
        rows++;
      }
    } else {
      strLength++;
      if (strLength > rows * num) {
        textArr.push(text.slice(str, i));
        str = i;
        rows++;
      }
    }
  }
  textArr.push(text.slice(str, text.length));
  return textArr;
}


(2)已知一行的高度为 15rpx,则可获得描述区域的高度为 15*textArr.length

3.4 记录维护每一列的最终高度


3.5 下滑不断加载填充

为了提高性能,减少每一次 setData 的数据量,选择二位数组的存储结构。

this.setData({
    ['phototListLeft[' + page + ']']: phototListLeft,
    ['phototListRight[' + page + ']']: phototListRight
});


本实例亮点:
  1. 使用二维数组存储,减少每次 setData 的数据量,有效提高了性能;
  2. 图片的描述内容也是随机的,高度不固定,通过动态计算,获取图片描述区域的高度;
  3. 因为图片宽度单位为px,故为了在各个手机能完美适配,通过单位转化,完美适配;
  4. 对每张图片显示前,设置随机的填充背景。