前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CSS&JavaScript:你究竟会几种多列布局?

CSS&JavaScript:你究竟会几种多列布局?

作者头像
西南_张家辉
发布2022-03-08 16:28:59
4630
发布2022-03-08 16:28:59
举报
文章被收录于专栏:张家辉的树屋张家辉的树屋

α 产品经理有个需求-多列布局的实现

  • 产品-彦祖 :
    • 家辉啊,我需要一个这样的场景展示数据,可以 自定义列数 ,后端数据返回的就是数组,你看你前端咋弄啊
  • 切图仔-渣渣辉 :
    • 好的彦祖, 自定义多列 嘛简单。思考 ing: 我有一个数组 list,输入对应的列数 col,就可以展示对应的列数,大概的 demo 我都写好了在下面
代码语言:javascript
复制
const cols:number = 3;
const list:Array<any> = [1,2,3,4,5,6,7]
<MultiBox columns={cols} list={list}/>

// show list
1 | 2 | 3
4 | 5 | 6
7 |   |

β 思考🤔 column-conut 实现

  • 多列展示,这还不简单嘛,flex 就是天然的多列啊,看了下文档发现不能自定义列数;想起常用的 column-count css 属性,先用字符串试试, 在实际使用数组的时候发现不好使;
  • 我们来看看 column-count 的定义
代码语言:javascript
复制
column-count CSS属性,描述元素的列数。
column-count: 3;
column-count: auto;

Block containers except table wrapper boxes

> 定义:<number> 是个严格的正数 <integer> ,用来描述元素内容被划分的理想列数. 假如 column-width (en-US)也被设置为非零值, 此参数仅表示所允许的 "最大列数"

• 注意上面的 最大列数 这里就是了,你指定的 number 并不一定是现在的列数,而是最大列数

代码语言:javascript
复制
import React from "react";
type IMultiBoxProps = {
  cols?: number;
  list: string | Array<any>;
};

const MultiBox = (props: IMultiBoxProps) => {
  const { cols = 1, list } = props;
  return (
    <div
      style={{
        columnCount: cols
      }}
    >
      {Array.isArray(list) ? list.join("") : list}
    </div>
  );
};

export default function App() {
 const defaultMultiBox1Props = {
    cols: 3,
    list:
      "当我年轻的时候,我梦想改变这个世界;当我成熟以后,我发现我不能够改变这个世界,我将目光缩短了些,决定只改变我"
  };
  const defaultMultiBox2Props = {
    cols: 3,
    list: [1, 2, 3, 4, 5, 6, 7, 8, 9]
  };

  return (
    <div className="App">
      <h1>Test MultiBox</h1>
      <MultiBox {...defaultMultiBox1Props} />
      <MultiBox {...defaultMultiBox2Props} />
    </div>
  );
}
改进
  • 既然 div 不行,ul>li 的文字排列可以吧, 把 list 的内容放进 li 中,想到了就做;初看没问题,搞定;
代码语言:javascript
复制
const MultiBox = (props: IMultiBoxProps) => {
  const { cols = 1, list } = props;

  return (
    <div>
        <ul style={{
            columnCount: cols
        }}>
            {list.map(val => <li>{val}</li>)}
        </ul>
    </div>
  );
};
column-count 简易算法
  • 彦祖:渣渣辉啊,你这个 5 列的时候有 bug 啊!是不是我操作有问题?
代码语言:javascript
复制
list = [1, 2, 3, 4, 5, 6, 7, 8, 9];

<MultiBox cols={3} list={list} />

// 3 列没问题
| 1 | 4 | 7 |
| 2 | 5 | 8 |
| 3 | 6 | 9 |

<MultiBox cols={6} list={list} />

// 只有 5 列 ?
| 1 | 3 | 5 | 7 | 9
| 2 | 4 | 6 | 8 |

这里就要提到上面的此参数仅表示所允许的 "最大列数"这个坑了

  • 我们来看 column-count 的计算方法, 首先计算每列可以承载最大的 items 数, 我们来试着模拟计算一下
代码语言:javascript
复制
const cols = 6;
const list = [1,2,3,4,5,6,7,8,9];
const result = [];
const countSize = Math.ceil(list.length / cols); // 2

for (let i = 0, len = list.length; i < len; i += countSize) {
    result.push(list.slice(i, i + countSize));
}
// [1,2]
// [3,4]
// [5,6]
// [7,8]
// [9]
反思 chunk 二维数组实现
  • 可以看到上面只有 5 列,问题就出现了,当我们的承载数足够的时候,这种按位优先补偿的算法就有明显的问题,但是也符合上面提到的最大列数原则,但是这里 彦祖 可是要求符合 cols 的数量。
  • column-count 不能满足,既然我们已经透析了它的算法为什么不改进一下啦?col 和 row 的网格布局,本质可以看做一个二维数组,我们可以先搞一个 table[cols] 的数组,然后按照每列插值保证列数优先,就安全了,能保证定义多少列就展示多少列。
代码语言:javascript
复制
const cols = 6;
const list = [1,2,3,4,5,6,7,8,9];

function chunker(cols, lists){
    const table = new Array(cols); 
    for (let i = 0; i < table.length; i++) {
        table[i] = new Array(); 
    }

    while (lists.length > 0) {
        // insert one rows
        for (let col = 0; col < table.length; col++) {
            table[col].push(lists.shift());
        }
    }
    return table.filter(Boolean);
}
chunker(cols, list)

// [1,7]
// [2,8]
// [3,9]
// [4]
// [5]
// [6]
  • css 和 tsx 模块实现
代码语言:javascript
复制
// css
.flex-direction-column{
    flex-direction: column;
}

.flex {
    display: flex;
}

// tsx
const MultiBox = (props: IMultiBoxProps) => {
  const { cols = 1, list } = props;

  const chunks = chunker(cols, list);

  return (
    <div className="flex">
        {chunks.map(col => 
            <div className="flex-direction-column">
                {col.map(item => item)}
            </div>
        )}
    </div>
  );
};

γ gird 布局 实现

  • 哪还有什么 css 属性能直接展示自定义多列啦?除了 flex,当然还有 gird 网格布局了,这下马上去看了 gird 的属性文档;
    • 遇事不决 阮一峰教程
    • 发现了这样一个属性,这不完美解决了多列布局的问题嘛
代码语言:javascript
复制
.gird-layout {
  display: grid;
  grid-template-columns: repeat(3, 33.33%); 
  // 三列布局
}
  • 完整代码(伪代码)
代码语言:javascript
复制
const MultiBox = (props: IMultiBoxProps) => {
  const { cols = 1, list } = props;
  
  return (
    <div
      style={{
        display: 'gird',
        gridTemplateColumns: repeat(cols, 1/cols);
      }}
    >
      {list.map( item => <div>{item}</div>)}
    </div>
  );
};
  • 留个问题:这里的 gridTemplateColumns: repeat(cols, 1/cols); repeat 不能直接使用, gird 方法是找到了,有什么优雅的方法解决这个问题啦?
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021/05/25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • α 产品经理有个需求-多列布局的实现
  • β 思考🤔 column-conut 实现
    • 改进
      • column-count 简易算法
      • 反思 chunk 二维数组实现
  • γ gird 布局 实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档