#javascript #reactjs
#javascript #reactjs
Вопрос:
У меня длинная форма, которая имеет столбец смешанного типа. Я имею в виду, что какое-то поле будет иметь ширину 100%, а какое-то поле будет составлять около 33%, чтобы я мог отображать 3 поля в столбце и так далее. Это я мог бы сделать без итерации, но как это можно сделать, если поля отображаются с итерацией, чтобы избежать повторения кода?Я также создал изолированную среду, и я не использую сторонний css-фреймворк, такой как bootstrap, просто гибкий или, может быть, сетка будет работать.
Вот как я пытался:
const formFields = [
{ id: 1, name: "first_name", component: TextField, label: "First Name" },
{ id: 1, name: "last_name", component: TextField, label: "Last Name" },
{ id: 1, name: "age", component: TextField, label: "Age" },
{ id: 1, name: "city", component: TextField, label: "City" },
{ id: 1, name: "state", component: TextField, label: "State" },
{ id: 1, name: "country", component: TextField, label: "Country" }
];
const FlexibleForm = () => {
return (
<React.Fragment>
<Form onSubmit={() => console.log("something")}>
<FlexRow>
<FlexColumn size={12}>
{formFields.map(({ id, name, label, component }) => {
return (
<Field
key={id}
name={name}
label={label}
component={component}
/>
);
})}
</FlexColumn>
</FlexRow>
<h2>Another without iteration</h2>
<FlexRow>
<FlexColumn size={6}>
<Field name="first_name" label="First Name" component={TextField} />
</FlexColumn>
<FlexColumn size={6}>
<Field name="last_name" label="Last Name" component={TextField} />
</FlexColumn>
</FlexRow>
<FlexRow>
<FlexColumn size={12}>
<Field name="age" label="Age" component={TextField} />
</FlexColumn>
</FlexRow>
<FlexRow>
<FlexColumn size={4}>
<Field name="city" label="City" component={TextField} />
</FlexColumn>
<FlexColumn size={4}>
<Field name="state" label="State" component={TextField} />
</FlexColumn>
<FlexColumn size={4}>
<Field name="country" label="Country" component={TextField} />
</FlexColumn>
</FlexRow>
</Form>
</React.Fragment>
);
};
export default reduxForm({
form: "form"
})(FlexibleForm);
export const FlexRow = styled.div`
display: flex;
div {
margin-right: 10px;
}
`;
export const FlexColumn = styled.div`
width: ${props => (props.size / 12) * 100}vw;
`;
Вот ссылка на codesandbox https://codesandbox.io/s/l7lm1qp0pq
Комментарии:
1. В чем вопрос?
2. теперь вопрос выделен жирным шрифтом. Как я могу отображать поля в разных столбцах с помощью итерации, что я делал без использования итерации?
3. Возможно, в вашем
FlexRow
компоненте вы можете добавить некоторые реквизиты, такие как массив объектов,[{name: "city", "label": "city", "component": <TextField />}, {name: "state", "label": "state", "component": <TextField />}, .....]
а затем создать условие для проверки количества элементов в массиве, если это три элемента, затем создайте 3 гибких столбца размером 4. Допустим, вы вызываете свой реквизитitemsInRow
, затемFlexRow
вы можете написать что-то вроде`this.props.itemsInRow.map( () => <Размер гибкой колонки={Math.round(12/this.props.itemsInRow.length)}> и т.д.4. можете ли вы воспроизвести пример с вашей концепцией, разветвляя мой код из песочницы, пожалуйста?
5. Ниже приведено несколько решений, но я хотел бы перефразировать великого Иэна Малкольма: «Вы были так озабочены тем, можете ли вы это сделать, что вы не задумывались, стоит ли вам это делать». Сохраняет ли этот код «динамическим», решая что-либо, или просто усложняет ваш код?
Ответ №1:
Это <FlexRow>
компонент
const FlexRow = props => {
return (
<div style={{ display: "flex" }}>
{props.elements.map((element, index) => {
const obj = element.component;
return (
<FlexColumn key={index} size={Math.round(12 / props.elements.length)}>
<Field
name={element.name}
label={element.label}
component={obj[Object.keys(obj)[0]]}
/>
</FlexColumn>
);
})}
</div>
);
};
Это <FlexColumn>
компонент
const FlexColumn = styled.div`
width: ${props => (props.size / 12) * 100}vw;
margin-right: 10px;
`;
Ваш <FlexibleForm>
должен выглядеть так :
const FlexibleForm = () => {
return (
<React.Fragment>
<Form onSubmit={() => console.log("something")}>
<FlexRow
elements={[
{ name: "first_name", label: "First Name", component: {TextField} },
{ name: "last_name", label: "Last Name", component: {TextField} }
]}
/>
<FlexRow
elements={[{ name: "age", label: "Age", component: {TextField} }]}
/>
<FlexRow
elements={[
{ name: "city", label: "City", component: {TextField} },
{ name: "state", label: "State", component: {TextField} },
{ name: "country", label: "Country", component: {TextField} }
]}
/>
</Form>
</React.Fragment>
);
};
Компонент <FlexRow>
будет зацикливаться внутри своих реквизитов elements
и создаст a <FlexColumn>
с хорошим размером и хорошими атрибутами.
В общем, он выполнял цикл внутри реквизита elements
, который представляет собой массив, и возвращал размер (12, деленный на количество имеющихся у вас строк), вы можете изменить это значение, если хотите, с помощью простого условия, например :
element.size ? element.size : Math.round(12 / props.elements.length)
и добавьте size
элемент в свой elements
массив
{ name: "first_name", label: "First Name", size: 6, component: {TextField} }
Затем он добавляет метку и имя. И, наконец, он добавляет выбранный вами компонент, в этом примере это <TextField>
Это позволит избежать повторения вашего кода. Вот CodeSandbox, чтобы показать вам пример!
Жаль, что я вам не помог.
Комментарии:
1. Мне нравится это решение, но я думаю, что проблема, с которой я сталкиваюсь (на самом деле, с вопросом), заключается в том, что избегание повторения кода в этом экземпляре значительно усложняет задачу. Решение, которое мне нравится больше всего, было оригинальным. он явный, его легко изменять и отлаживать, и новый разработчик, который приходит, может его прочитать..
2. @Beaulne да, я думаю, вы правы, единственная проблема, которую я вижу в его итерации, которая намного проще, чем моя, заключается в том, что он не может выбрать размер поля. Я предпочитаю использовать
<Component>
, и<ComponentItem>
для меня это проще читать и добавлять свойства
Ответ №2:
Нет особого смысла использовать flex, если вы не используете flex-wrap.
Если вы хотите сделать это с помощью простого float:
const formFields = [
{ id: 1, name: "first_name", component: TextField, label: "First Name",size: 6 },
{ id: 1, name: "last_name", component: TextField, label: "Last Name", size: 6 },
{ id: 1, name: "age", component: TextField, label: "Age", size: 12 },
{ id: 1, name: "city", component: TextField, label: "City", size: 4 },
{ id: 1, name: "state", component: TextField, label: "State", size: 4 },
{ id: 1, name: "country", component: TextField, label: "Country", size: 4 }
];
const Form = styled.form`
width: 100%;
`;
const FlexColumn = styled.div`
float: left;
width: ${props => (props.size / 12) * 100}%;
`;
const FlexibleForm = () => (
<React.Fragment>
<Form onSubmit={() => console.log("something")}>
{formFields.map(({ id, name, label, component, size }) => {
return (
<FlexColumn size={size}>
<Field key={id} name={name} label={label} component={component} />
</FlexColumn>
);
})}
</Form>
</React.Fragment>
);
Комментарии:
1. Работает ли это без переноса
<FlexColumn>
в a<FlexRow>
?2. я не оборачиваю их