Как я могу заполнить 3 столбца одним массивом строк в порядке столбца - PullRequest
0 голосов
/ 07 августа

У меня есть такой массив строк:

const checkboxItems = [
    'a', 'b', 'c',
    'd', 'e', 'f',
    'g', 'h', 'i',
]

, и я хочу заполнить три столбца по порядку столбцов, поэтому результат будет:

a d g
b e h
c f i

У меня компонент оболочки с css, например:

const CheckboxWrapper = styled('div')`
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
`;

, и мне нужно отобразить компоненты флажка в трех столбцах с метками из checkboxItems. Мой компонент выглядит так:

<CheckboxWrapper>
        {
            checkboxItems.map(item => {
                return <Checkbox
                    key={'checkBox'}
                    checked={false}
                    onClick={() => { }}
                >
                    <Label>{item}</Label>
                </Checkbox>
            })
        }
    </CheckboxWrapper>

Обратите внимание, что мой текущий код отображает элементы следующим образом:

a b c
d e f
g h i

Что я делаю не так? Будем признательны за пример!

Ответы [ 3 ]

2 голосов
/ 07 августа

Поскольку вы .map() поверх checkboxItems, они отображаются в порядке появления, тогда как вам нужно сделать их транспонированными.

Чтобы получить желаемый результат, общий подход состоит в том, чтобы сломать ваш источник массив на фрагменты длиной 3 (количество столбцов), транспонированных в соответствии с желаемым порядком:

itemsToRender = Array(Math.ceil(checkboxItems.length/3))
          .fill()
          .map((_, i, s) => 
            Array(3)
              .fill()
              .map((_,j) => 
                checkboxItems[i+j*s.length]))

Ниже приводится живая демонстрация этого подхода:

const { render } = ReactDOM,
      rootNode = document.getElementById('root')
      
const App = () => {
  const checkboxItems = ['First name','Last name','Email','Phone','Address','Gender','City','Postcode','Country/State','Country','Lifetime value','Tickets in period','Revenue in period','Permission to contact','Customer ID','Account ID','AS Customer tags','Product/Event','Price Category','Section','Row','Seat'],
        
        itemsToRender = Array(Math.ceil(checkboxItems.length/3))
          .fill()
          .map((_, i, s) => 
            Array(3)
              .fill()
              .map((_,j) => 
                checkboxItems[i+j*s.length]))
          
  return (
    <div className="wrapper">
      {
        itemsToRender.map((row, rowIdx) => (
          <div key={rowIdx} className="row">
            {
              row.map((item, itemPos) => item && (
                <label key={itemPos} className="cell">
                  <input type="checkbox" value={item} />
                  {item}
                </label>
              ))
            }
          </div>
        ))
      }
    </div>
  )          
}

render (
  <App />,
  rootNode
)
.wrapper {
  display: flex;
  flex-direction: column;
}

.row {
  display: flex;
  flex-direction: row;
}

.cell {
  width: 150px;
  height: 50px;
  margin: 5px;
  background-color: cadetblue;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: flex-start;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>

Другой подход (продолжить компоновку grid и переупорядочить элементы, используя, в частности, функции CSS и repeat()) состоит в том, чтобы сделать использование стиля Material-UI (как в данном случае) и динамическая установка grid-template-rows в зависимости от количества строк, необходимых для обертывания вашего списка:

const  { render } = ReactDOM,
       { FormControlLabel, Checkbox } = MaterialUI,
       { makeStyles } = MaterialUI

const rootNode = document.getElementById('root')

const useStyles = rowNum => makeStyles({
  wrapper: {
    display: 'grid',
    gridTemplateRows: `repeat(${rowNum}, 1fr)`,
    gridAutoFlow: 'column'
  }
})

const App = () => {
  const checkboxItems = ['First name','Last name','Email','Phone','Address','Gender','City','Postcode','Country/State','Country','Lifetime value','Tickets in period','Revenue in period','Permission to contact','Customer ID','Account ID','AS Customer tags','Product/Event','Price Category','Section','Row','Seat'],
        classes = useStyles(Math.ceil(checkboxItems.length/3))()
        
  return(
    <div className={classes.wrapper}>
      {
        checkboxItems.map((item, itemIdx) => (
          <FormControlLabel
            key={itemIdx}
            control={
              <Checkbox
                name={item}
              />
            }
            label={item}
          />
        ))
      }
    </div>
  )
}

render (
  <App />,
  rootNode
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.development.js"></script><div id="root"></div>
2 голосов
/ 07 августа

Установить grid-auto-flow на column и grid-template-rows на 3 x 1fr:

const CheckboxWrapper = styled('div')`
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  grid-auto-flow: column;
`;
0 голосов
/ 07 августа

Попробуйте это,

const checkboxItems = [
    'a', 'b', 'c',
    'd', 'e', 'f',
    'g', 'h', 'i',
]
const sortedCheckBox = []
const col = 3;

for (let i = 0; i < col; i++) {
  for (let j = i; j < checkboxItems.length; j += col) {
    sortedCheckBox.push(checkboxItems[j])
  }
}

console.log(sortedCheckBox)
...