📔引言
在前端开发中,瀑布流布局是一种常见的页面展示方式。近期我对相关应用场景和解决方案进行了整理,其中涵盖了简单算法动态规划(DP)、前端基础知识以及业务场景的深入思考。
📔理解瀑布流布局
瀑布流,又被称为瀑布流式布局,是一种流行的页面布局方式,英文名称为"Masonry Layouts"。不同于传统的分页显示,它以视觉上参差不齐的多栏布局为特点,最早由 Pinterest 首次运用。
在移动端,双列瀑布流布局变得更为普遍。该布局在展现每个元素时,能够以自身情况合理占据空间,使得每个元素的宽高不一致,左右依次调整排列,最终占据最小的屏幕高度。结合无限加载的设计,瀑布流不仅考虑了用户心理、展示美观,更关注用户体验。
以腾讯课堂APP的瀑布流为例:
🍚应用场景
基于瀑布流的优缺点,我们可以合理选择在什么情况下采用瀑布流布局:
以图片为主的内容: 当内容主要为图片时,瀑布流是更佳的选择。由于图片占用较大空间,而人脑对图像的理解速度相对更快,分页显示可能导致用户频繁翻页,影响沉浸式体验。瀑布流解决了这一问题。
信息相对独立: 当信息之间相对独立时,瀑布流是更好的选择。如果信息关联性较强,用户可能需要大量回溯查看前后信息。相反,若信息相对独立,使用瀑布流可以让用户同时获取来自不同来源的信息。
匹配度无明显区分: 当信息与搜索匹配度没有明显区分度时,可以采用瀑布流。瀑布流呈现的信息与用户搜索的匹配度大致相同,相较于分页显示,更容易引起用户兴趣。
用户目的性不强: 当用户没有特定目的需要查找信息时,瀑布流是更好的选择。分页查找对于有明确需求的用户更为方便,而瀑布流则能增加用户停留时间和带来意想不到的收获。
引用一篇文章的总结,瀑布流能够有效引导用户充分利用碎片化的时间,最大化用户留存和使用时间。
在选择瀑布流布局时,需要综合考虑以上场景,以便更好地适应具体业务需求。
🧪构建高性能H5双列瀑布流的实现方法
在前端开发中,瀑布流布局是一种常见的设计方式,而实现瀑布流则有多种方式,包括multi-column、grid和Flexbox等。本文不深入说明每种方式的具体实现,建议不熟悉的读者自行查阅相关资料。综合考虑兼容性和易用性,我们推荐使用Flexbox布局方案。
📰HTML结构和CSS设置
一般而言,HTML结构如下所示(以微信小程序为例):
对应的CSS设置如下:
在这里,瀑布流容器的flex设置实现了横向布局,而列容器采用了纵向布局。
🔒数据元组分析
数据元组分为总数据couponList,左侧列数据left和右侧列数据right。我们将在后续分析中关注优化分配方式。
🔒高性能H5双列瀑布流的关键
为了实现一个高性能、高体验的H5双列瀑布流,我们首先选择了使用Flexbox实现布局。在技术实现方面,我们要求支持无限向下滚动加载数据,以使读者更专注于业务背景。其他场景可在留言区讨论,本文将专注于当前场景,不做过多赘述。
更加精准地说,在双列瀑布流的应用场景中,我们可以根据元素卡片高度是否固定以及顺序是否严格固定来分为元素高度分化场景和顺序分化场景。具体如下:
🍉元素高度分化场景:
A1场景:每个元素的高度都是固定的;
A2场景:每个元素的高度不固定,但可以通过数据类型估算自身相对于屏幕宽度的百分比高度;
A3场景:元素的高度不固定,且无法在渲染之前确定,只有在渲染完成后才能确认高度。
🍉顺序分化场景:(前提是结合无限加载)
B1场景:元素的相对顺序严格一致;
B2场景:元素的相对顺序宽泛性一致。
接下来,我们将对每个具体场景进行详细分析,并优化实现细节。
在A1场景下,可以采用最简单的数据排列方式,即左右交替排列。以下是一段简洁的代码实现:
对于A2场景,需要动态分配左右两列的元素,具体是根据当前高度差来进行分配。简而言之,将元素分配到当前高度较短的那一列。此方法同时适用于B1场景。以下是对应的代码:
对于A3场景,由于无法预知真实渲染后的高度,特别是在图片瀑布流场景中,建议采用A2场景的方式。即预先获取图片真实高宽,尽管这样做会带来一定的性能损耗。以下是获取图片信息的异步函数:
以上是对A1、A2和A3场景的处理方法,使得它们更具可读性和清晰性。
📔进阶优化:误差矫正
在A2场景中,由于每个卡片的高度无法精确渲染,特别是在移动端H5中使用Rem单位、适配不同设备类型的情况下,计算的精度差和像素误差可能导致计算左右高度差时的一定误差。在无限滚动的基础上,这种误差可能会持续累积,最终导致布局策略的失败。因此,需要在每次加载数据后对左右高度差进行矫正。
简单的矫正方式是在左右列容器的尾部增加一个高度为0px的隐藏锚点元素,每次渲染结束后获取锚点元素的offsetTop值,从而更新左右两侧的高度差。
🌰以下是HTML结构的示例:
🌰下面是小程序中用于更新差值的代码:
在这里,leftData和rightData表示新增的排列数据,diffValue表示左右两列高度差值。然而,实际上diffValue和左右锚点的高度差值存在误差,因此通过这种方式进行手动矫正。
📱通过DP算法获取最优排列
在A2场景中,通过计算高度差向高度低的一列添加元素并不是一个完美的解决方案。在极端情况下,例如最后一个元素过高,会导致底部左右的高度差过大,甚至超过一个常见元素的高度。这一方面没有充分利用屏幕高度,另一方面,巨大的高度差也会对用户体验产生负面影响。
为了解决这个问题,我们引入了简单的DP(Dynamic Programming)算法。假设我们已知所有待排列元素的高度,可以计算出这些元素真实占据的总高度H。如果将两个列容器视为联通的水柱,其元素总高度H / 2就是最佳占据高度。由于左右排列高度一致的情况很难实现,获取最靠近H / 2的排列高度即为最佳排列高度。进而,将问题转化为背包问题,即在H / 2容量的背包内,如何放置尽可能多的元素。
🌰以下是使用DP算法解决如何获取最优排列的示例代码:
这段代码通过DP算法动态规划地计算了最优排列,以优化在A2场景下的瀑布流布局。
📔优化列容器中的排列
在实际业务场景中,我们常常对排列顺序有一些要求,尤其是在广告和推荐算法中更是如此。在这方面,前端可以通过一些优化手段来提升用户体验。具体而言,我们可以通过调整列容器内部的排序,以及在不同列容器之间置换相同元素的方式,来尽可能确保高优先级的元素出现在靠前的位置。
🚀最终的效果演示如下: