Alpha product manager has a requirement – implementation of multi-column layout

  • Products – Daniel:
    • Jiahui, I need such a scene to show the data, okCustomize the number of columnsBack end data return is the array, you see what you do front end
  • Cheetuzai – Slag Hui:
    • Okay, Daniel,Custom multiple columnsIt is simple. Think ing: I have an arraylist, enter the corresponding column numbercol, you can show the corresponding number of columns, roughlydemoI’ve written it all down here
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 |   |
Copy the code

β thinking 🤔 column-Conut implementation

  • Flex is a natural multi-column display. If you look at the documentation, you can’t customize the number of columns. Think of the usualcolumn-countCSS properties, try using strings first, in practiceAn array ofWhen found not to make;
    • See CodesandBox for details
  • Let’s seecolumn-countThe definition of
Column-count CSS property, which describes the number of columns of an element. column-count: 3; column-count: auto; Block containers except table wrapper boxesCopy the code

Definition: is a strictly positive number that describes the ideal number of columns in which the element’s contents are divided. If column-width (en-us) is also set to non-zero, this parameter only represents the “maximum number of columns” allowed.

• The maximum number of columns you specify is not necessarily the current number of columns, but the maximum number of columns

import React from "react";
typeIMultiBoxProps = { 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:
      "When I was young, I dreamed of changing the world. As I grew older, I saw that I could not change the world, so I shortened my vision and decided to change only me."
  };
  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>
  );
}
Copy the code

To improve the

  • Since div is not available, ul>li can arrange text, put the contents of the list into li, and do it as you think; Okay at first glance, done;
const MultiBox = (props: IMultiBoxProps) = > {
  const { cols = 1, list } = props;

  return (
    <div>
        <ul style={{
            columnCount: cols}} >
            {list.map(val => <li>{val}</li>)}
        </ul>
    </div>
  );
};
Copy the code
Column-count simple algorithm
  • Daniel: Slag hui ah, you have a bug in this 5 columns ah! Is there something wrong with my operation?
list = [1.2.3.4.5.6.7.8.9];

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

// Column 3 is ok
| 1 | 4 | 7 |
| 2 | 5 | 8 |
| 3 | 6 | 9 |

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

// Only 5 columns?
| 1 | 3 | 5 | 7 | 9
| 2 | 4 | 6 | 8 |
Copy the code

It should be noted that this parameter only represents the “maximum number of columns” allowed

  • Let’s take a look atcolumn-countFirst, calculate the maximum number of items that each column can carry. Let’s try to simulate the calculation
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]
Copy the code
Rethinking the chunk two-dimensional array implementation
  • You can see there’s only5When we have enough loads, this bit-first compensation algorithm has obvious problems, but it also conforms to the maximum number of columns mentioned above, but hereDanielBut the requirements fitcolsThe number of.
  • Column-count doesn’t work, so why don’t we improve the algorithm now that we’ve looked at it? The grid layout of col and Row can essentially be viewed as one2 d arrayWe can get one firsttable[cols]Then interpolate each column in order to ensure that the number of columns is first, and it is safe to display as many columns as you can define.
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(a); }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]
/ / [3, 9]
/ / [4]
/ / [5]
/ / [6]
Copy the code
  • CSS and TSX modules
// 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>
  );
};
Copy the code

γ GIRD layout implementation

  • Where is the CSS property that directly displays custom multicolumns? In addition to Flex, there is also girD grid layout.
    • Ruan yifeng tutorial
    • Found such a property, it is not perfect to solve the multi-column layout problem
.gird-layout {
  display: grid;
  grid-template-columns: repeat(3.33.33%); // three column layout}Copy the code
  • Complete code (pseudocode)
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>
  );
};
Copy the code
  • One question: heregridTemplateColumns: repeat(cols, 1/cols);The girD method can not be used directly. What is the elegant way to solve this problem?