赞
踩
背景:项目中本来使用的是multi-columns多列布局,但是后来随着业务的增加,布局中的元素的高度不是固定的了,而是增加了一个Antd的Collapse的展开折叠操作。这种情况下,使用纵向的multi-columns布局就使得元素高度变化比较大时,就会随着高度自动重排,有时会换列,这样的话操作复杂性就很高,不利于用户使用,故修改为横向瀑布流的方式。以下对两种方式进行一个简单的介绍和记录。
纯css写法,省时省力
排列顺序只能从上到下,再从左到右。只能用于数据固定, 无法动态的加载追加,对于滚动到底部加载新数据则无法实现。
column-count : 定义列数
column-gap :列与列之间的间隔
有时候页面会出现在前几列的最后一个元素的内容被自动断开,一部分在当前列尾,一部分在下一列的列头。这时候子元素可以用 break-inside设置为不被截断 avoid来控制。
break-inside: avoid; // 不被截断 默认值是auto,会被截断
- .card{
- column-count: 3; // 定义三列
- column-gap: 20px; // 列与列的距离为20px
-
- .card-item{
- text-align: center;
- width: 216px;
- border-radius: 16px;
- grid-row-start: auto;
- margin-bottom: 20px;
- break-inside: avoid; // 不被截断
- }
- }
横向布局,更符合使用习惯
实现复杂度较高,元素较多时,计算量较大,需要考虑重复渲染的问题
用flex弹性布局+计算元素高度实现布局。第一列元素排列之后,每次元素的追加都选择当前高度最小的那一列。
结构:
- <div className={styles.flexLeftList}>
- <div className={styles.columnItem}>
- {generateDOM(columnListLeft.current)}
- </div>
- <div className={styles.columnItem}>
- {generateDOM(columnListCenter.current)}
- </div>
- <div className={styles.columnItem}>
- {generateDOM(columnListRight.current)}
- </div>
- </div>
-
- const generateDOM = (list) => (
- list.map((item) => {
- return (
- <div className={styles.module} key={item.id} id={item.id}>
- {/* 二级菜单名称 */}
- <div className={`${styles.title}>
- {item.name}
- </div>
- {/* 三级菜单 */}
- {item?.children?.map((childItem) => {
- return (
- <div style={{display: 'block'}}>
- <Item
- type={ItemType}
- item={childItem}
- key={childItem.id}
- />
- </div>
- );
- })}
- </div>
- );
- })
- )
js:
- // 计算flex布局每列的数据项
- const caLFlex = (mList) => {
- if(!mList.length) return;
- let arrLeft: IMenuItem[] = []; // 第一列的数据
- let arrCenter: IMenuItem[] = []; // 第二列的数据
- let arrRight: IMenuItem[] = []; // 第二列的数据
- let countArray_left: number[] = []; // 根据数量判断高度
- let countArray_center: number[] = [];
- let countArray_right: number[] = [];
-
- mList.forEach((item,index) =>{
- if(index === 0){ // 第一行中的元素无需判断,直接加到新的数组中
- countArray_left.push(item?.children?.length ?? 0);
- arrLeft.push(item);
- return;
- }
- if(index === 1){
- countArray_center.push(item?.children?.length ?? 0);
- arrCenter.push(item);
- return;
- }
- if(index === 2){
- countArray_right.push(item?.children?.length ?? 0);
- arrRight.push(item);
- return;
- }
-
- // 累计各行元素数目
- const countTotal_left = countArray_left.length ? Array.from(countArray_left).reduce(( acc, cur ) => acc + cur) : 0; // 第一列的总个数
- const countTotal_center = countArray_center.length ? Array.from(countArray_center).reduce(( acc, cur ) => acc + cur) : 0; // 第二列的总个数
- const countTotal_right = countArray_right.length ? Array.from(countArray_right).reduce(( acc, cur ) => acc + cur) : 0; // 第三列的总个数
-
- // 找到最小值
- let minNumber = Math.min(countTotal_left,countTotal_center,countTotal_right);
- switch (minNumber) {
- case countTotal_left:
- countArray_left.push(item?.children?.length ?? 0);
- arrLeft.push(item);
- break;
- case countTotal_center:
- countArray_center.push(item?.children?.length ?? 0);
- arrCenter.push(item);
- break;
- case countTotal_right:
- countArray_right.push(item?.children?.length ?? 0);
- arrRight.push(item);
- break;
- }
- });
-
- // 重新将数据赋值给各列数组
- columnListLeft.current = arrLeft;
- columnListCenter.current = arrCenter;
- columnListRight.current = arrRight;
- };
css:
- // flex横向布局
- .flex-left-list {
- width: 100%;
- min-height: 100%;
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: space-around;
- .column-item{
- width: calc(100% / 3);
- .module{
- display: flex;
- flex-direction: column;
- height: fit-content;
- padding: 0 16px 30px 16px;
- .title {
- font-size: 16px;
- color: rgba(0,0,0,0.85);
- margin-bottom: 10px;
- padding-left: 14px;
- }
- }
- }
- }
参考链接:https://blog.csdn.net/Smile_666666/article/details/124728121 (大哥讲解更详细,有需要可以去看,同时多谢大哥提供思路~)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。