当前位置:   article > 正文

多列不等高布局之横向瀑布流和纵向瀑布流

横向瀑布流

背景:项目中本来使用的是multi-columns多列布局,但是后来随着业务的增加,布局中的元素的高度不是固定的了,而是增加了一个Antd的Collapse的展开折叠操作。这种情况下,使用纵向的multi-columns布局就使得元素高度变化比较大时,就会随着高度自动重排,有时会换列,这样的话操作复杂性就很高,不利于用户使用,故修改为横向瀑布流的方式。以下对两种方式进行一个简单的介绍和记录。

一、 multi-columns多栏布局---纵向瀑布流

1. 优点:

纯css写法,省时省力

2. 缺点:

排列顺序只能从上到下,再从左到右。只能用于数据固定, 无法动态的加载追加,对于滚动到底部加载新数据则无法实现。

3. 两个重要属性:

column-count : 定义列数
column-gap :列与列之间的间隔

4. 注意点:

有时候页面会出现在前几列的最后一个元素的内容被自动断开,一部分在当前列尾,一部分在下一列的列头。这时候子元素可以用 break-inside设置为不被截断 avoid来控制。

 break-inside: avoid; // 不被截断 默认值是auto,会被截断

5. 实现代码:
  1. .card{
  2. column-count: 3; // 定义三列
  3. column-gap: 20px; // 列与列的距离为20px
  4. .card-item{
  5. text-align: center;
  6. width: 216px;
  7. border-radius: 16px;
  8. grid-row-start: auto;
  9. margin-bottom: 20px;
  10. break-inside: avoid; // 不被截断
  11. }
  12. }

 二、 横向瀑布流---泳道设计

1. 优点:

横向布局,更符合使用习惯

2. 缺点:

实现复杂度较高,元素较多时,计算量较大,需要考虑重复渲染的问题

3. 实现思路:

用flex弹性布局+计算元素高度实现布局。第一列元素排列之后,每次元素的追加都选择当前高度最小的那一列。

4. 算法思路:通过上面的分析则能了解瀑布流的思路了
  • 设计要分成的列数
  • 设置每列的 宽度一致
  • 每次插入的位置选择所有列高度最小 的位置,依次循环
5. 代码实现思路:
  • 由于是使用Collapse折叠结构,则计算时直接利用其子元素的个数来进行高度比较
  • 多少列则定义多少新的空数组,然后根据瀑布流的思路依次插入到空的数组即可
6. 代码实现

结构:

  1. <div className={styles.flexLeftList}>
  2. <div className={styles.columnItem}>
  3. {generateDOM(columnListLeft.current)}
  4. </div>
  5. <div className={styles.columnItem}>
  6. {generateDOM(columnListCenter.current)}
  7. </div>
  8. <div className={styles.columnItem}>
  9. {generateDOM(columnListRight.current)}
  10. </div>
  11. </div>
  12. const generateDOM = (list) => (
  13. list.map((item) => {
  14. return (
  15. <div className={styles.module} key={item.id} id={item.id}>
  16. {/* 二级菜单名称 */}
  17. <div className={`${styles.title}>
  18. {item.name}
  19. </div>
  20. {/* 三级菜单 */}
  21. {item?.children?.map((childItem) => {
  22. return (
  23. <div style={{display: 'block'}}>
  24. <Item
  25. type={ItemType}
  26. item={childItem}
  27. key={childItem.id}
  28. />
  29. </div>
  30. );
  31. })}
  32. </div>
  33. );
  34. })
  35. )

js:

  1. // 计算flex布局每列的数据项
  2. const caLFlex = (mList) => {
  3. if(!mList.length) return;
  4. let arrLeft: IMenuItem[] = []; // 第一列的数据
  5. let arrCenter: IMenuItem[] = []; // 第二列的数据
  6. let arrRight: IMenuItem[] = []; // 第二列的数据
  7. let countArray_left: number[] = []; // 根据数量判断高度
  8. let countArray_center: number[] = [];
  9. let countArray_right: number[] = [];
  10. mList.forEach((item,index) =>{
  11. if(index === 0){ // 第一行中的元素无需判断,直接加到新的数组中
  12. countArray_left.push(item?.children?.length ?? 0);
  13. arrLeft.push(item);
  14. return;
  15. }
  16. if(index === 1){
  17. countArray_center.push(item?.children?.length ?? 0);
  18. arrCenter.push(item);
  19. return;
  20. }
  21. if(index === 2){
  22. countArray_right.push(item?.children?.length ?? 0);
  23. arrRight.push(item);
  24. return;
  25. }
  26. // 累计各行元素数目
  27. const countTotal_left = countArray_left.length ? Array.from(countArray_left).reduce(( acc, cur ) => acc + cur) : 0; // 第一列的总个数
  28. const countTotal_center = countArray_center.length ? Array.from(countArray_center).reduce(( acc, cur ) => acc + cur) : 0; // 第二列的总个数
  29. const countTotal_right = countArray_right.length ? Array.from(countArray_right).reduce(( acc, cur ) => acc + cur) : 0; // 第三列的总个数
  30. // 找到最小值
  31. let minNumber = Math.min(countTotal_left,countTotal_center,countTotal_right);
  32. switch (minNumber) {
  33. case countTotal_left:
  34. countArray_left.push(item?.children?.length ?? 0);
  35. arrLeft.push(item);
  36. break;
  37. case countTotal_center:
  38. countArray_center.push(item?.children?.length ?? 0);
  39. arrCenter.push(item);
  40. break;
  41. case countTotal_right:
  42. countArray_right.push(item?.children?.length ?? 0);
  43. arrRight.push(item);
  44. break;
  45. }
  46. });
  47. // 重新将数据赋值给各列数组
  48. columnListLeft.current = arrLeft;
  49. columnListCenter.current = arrCenter;
  50. columnListRight.current = arrRight;
  51. };

css:

  1. // flex横向布局
  2. .flex-left-list {
  3. width: 100%;
  4. min-height: 100%;
  5. display: flex;
  6. flex-direction: row;
  7. flex-wrap: wrap;
  8. justify-content: space-around;
  9. .column-item{
  10. width: calc(100% / 3);
  11. .module{
  12. display: flex;
  13. flex-direction: column;
  14. height: fit-content;
  15. padding: 0 16px 30px 16px;
  16. .title {
  17. font-size: 16px;
  18. color: rgba(0,0,0,0.85);
  19. margin-bottom: 10px;
  20. padding-left: 14px;
  21. }
  22. }
  23. }
  24. }


参考链接:https://blog.csdn.net/Smile_666666/article/details/124728121 (大哥讲解更详细,有需要可以去看,同时多谢大哥提供思路~)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/174728?site
推荐阅读
相关标签
  

闽ICP备14008679号