Alpha product manager has a requirement – implementation of multi-column layout
- Products – Daniel:
- Jiahui, I need such a scene to show the data, ok
Customize the number of columns
Back end data return is the array, you see what you do front end
- Jiahui, I need such a scene to show the data, ok
- Cheetuzai – Slag Hui:
- Okay, Daniel,
Custom multiple columns
It is simple. Think ing: I have an arraylist
, enter the corresponding column numbercol
, you can show the corresponding number of columns, roughlydemo
I’ve written it all down here
- Okay, Daniel,
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 usual
column-count
CSS properties, try using strings first, in practiceAn array ofWhen found not to make;- See CodesandBox for details
- Let’s see
column-count
The 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 at
column-count
First, 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 fit
cols
The 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 one
2 d array
We 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: here
gridTemplateColumns: repeat(cols, 1/cols);
The girD method can not be used directly. What is the elegant way to solve this problem?