#javascript #html #css #reactjs
#javascript #HTML #css #reactjs
Вопрос:
Привет, я работаю над побочным проектом, в котором я хочу разработать компонент react, который может отображать детали на верхней панели с текстом и двумя кнопками, а внизу — иерархию, стилизованную под блок-схему меню. каждый пункт меню будет расширяться при нажатии на знак плюс и сворачиваться при нажатии на знак минус.
Я новичок в reactjs, я не знаю, как отображать такие компоненты, можете ли вы мне здесь помочь?
Если у вас есть какие-либо вопросы, пожалуйста, прокомментируйте ниже и заранее спасибо.
Комментарии:
1. Что-нибудь, что вы пробовали на данный момент?
2. Да, это не одно и то же, и есть много ограничений. material-ui.com/components/tree-view
3. Можете ли вы предоставить какой-нибудь образец объекта, с помощью которого вы хотите отобразить эту иерархию блок-схемы
Ответ №1:
Вы могли бы использовать рекурсивный подход, при котором вы отображаете дочерние (вложенные) элементы внутри компонента с помощью map
метода, если есть дочернее свойство и isOpen
значение true .
Структура данных представляет собой массив объектов, в котором каждый объект имеет title
, text
и children
свойство, которое представляет собой массив той же структуры. Это будет работать с данными любого уровня глубины.
const data = [{"title":"item-1","text":"Lorem ipsum dolor sit amet.","children":[{"title":"item-1-1","text":"Lorem ipsum dolor sit amet.","children":[{"title":"item-1-1-1","text":"Lorem ipsum dolor sit amet."},{"title":"item-1-1-2","text":"Lorem ipsum dolor sit amet."}]},{"title":"item-1-2","text":"Lorem ipsum dolor sit amet."}]},{"title":"Item 2","text":"Lorem ipsum dolor sit amet.","children":[{"title":"Item 4","text":"Lorem ipsum dolor sit amet."}]}]
const { useState } = React;
const App = ({ items }) => (
items.map((item, i) => (
<Item {...item} key={i}/>
))
)
const ItemHeader = ({ title, isOpen, setIsOpen }) => (
<div className="item-header">
<span>{title}</span>
<button onClick={() => setIsOpen(!isOpen)}>{isOpen ? '-' : ' '}</button>
</div>
)
const ItemBody = ({ text, children, isOpen }) => (
<div className={`item-body ${isOpen ? 'show' : 'hide'}`}>
<p>{text}</p>
</div>
)
const Item = ({ title, text, children }) => {
const [isOpen, setIsOpen] = useState(false);
return (
<div className="item">
<div class="item-content">
<ItemHeader
title={title}
isOpen={isOpen}
setIsOpen={setIsOpen}/>
<ItemBody
isOpen={isOpen}
text={text}
children={children}/>
</div>
<div class="item-children">
{children amp;amp; isOpen amp;amp; children.map((item, i) => <Item {...item} key={i}/>)}
</div>
</div>
)
}
ReactDOM.render(
<App items={data}/>,
document.querySelector('#root')
)
.item {
color: white;
font-size: 14px;
margin-bottom: 10px;
}
.item-content {
padding: 5px 10px;
border-radius: 5px;
background: #252525;
margin-bottom: 10px;
}
.item-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.item-header button {
cursor: pointer;
}
.item-body {
display: flex;
flex-direction: column;
}
.hide {
display: none;
}
p {
margin: 5px 0
}
.item-children {
margin-left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Комментарии:
1. Большое спасибо за ответ. Я уже создал аналогичные функции, основная проблема, с которой я сталкиваюсь, — это подключение каждого компонента с помощью строк, что-то вроде сообщений в Твиттере. как я могу добиться таких функций.
Ответ №2:
Отказ от ответственности. Когда люди спрашивают в комментариях «что вы пробовали до сих пор?», Они, кроме как помочь вам решить какую-то проблему, а не «сделать это за вас». Обязательно попробуйте что-нибудь, прежде чем слепо спрашивать.
Для ее создания вам не нужны библиотеки (из вашей текущей версии вопроса). Все, что вам нужно сделать, это реализовать составной шаблон компонента. Очень простой пример:
export class FlowItem extends React.Component {
render() {
const {header, children} = this.props;
return (
<div>
Ping from {header}
<div style={{marginLeft: '20px'}}>
{children}
<div/>
<div/>
);
}
}
И это пример использования ниже.
export class Content extends React.Component {
render() {
return (
<div
<FlowItem
header={"Very Top 1"}>
<FlowItem
header={"Parent 1"}>
<FlowItem/>
<FlowItem/>
<FlowItem
header={"Very Top 2"}>
<FlowItem
header={"Parent 1"}>
<FlowItem/>
<FlowItem
header={"Parent 2"}>
<FlowItem header={"Child 1"}/>
<FlowItem header={"Child 2"}/>
<FlowItem/>
<FlowItem
header={"Parent 3"}>
<FlowItem/>
<FlowItem/>
<div/>
);
}
}
Еще один простой пример, если вы хотите использовать с реальными объектами в массиве. Я думаю, что это ваш случай из вопроса:
export class Content extends React.Component {
render() {
const root = {
header: "Root 1",
children: [
{
header: "Parent 1",
children: [
{
header: "Child 1",
children: [
{
header: "Inner 1",
children: null
}
]
},
{
header: "Child 2",
children: null
},
{
header: "Child 3",
children: null
}
]
},
{
header: "Parent 2",
children: [
{
header: "Child 1",
children: null
},
{
header: "Child 2",
children: null
}
]
},
]};
return (
<div>
{this.getItemView(root)}
<div/>
);
}
getItemView = (node) => {
return (
<FlowItem
header={node.header}>
{node.children ?
node.children.map((obj, idx) => {
return (this.getItemView(obj));
}) : <div/>}
<FlowItem/>
);
};
}
Ответ №3:
Это также возможно с помощью ЧИСТОГО CSS и JS, проверьте это и расширяйте по мере необходимости.