介绍
音乐乐器合并压缩和扩展. 图形控制元素合并类似地崩溃和扩展. 这可以是分解大内容的解决方案,并允许用户专注于与他们相关的部分。
类似于 tabs 组件,一个合并组件由不同的部分组成,可以转移到打开和关闭,与 Tabs 组件不同,合并可以支持同时显示多个内容部分。
在本文中,您将创建一个简单的可重复使用的符号组件,其中有可以转移开关的部分,然后我们将修改该组件以支持同时打开多个部分,并指定哪些部分应该默认打开。
前提条件
要完成本教程,您将需要:
- Node.js 是本地安装的,您可以按照 如何安装 Node.js 和创建本地开发环境进行操作。
- 对 React 的一些熟悉。
本教程已通过 Node v16.6.2, npm
v7.21.0 和 react
v17.0.2 进行验证。
步骤1 - 设置项目
在此步骤中,您将使用 Create React App创建一个新项目,然后将删除在启动项目时安装的样本项目和相关文件。
要开始,创建一个新项目. 在终端中,运行以下脚本以使用create-react-app
安装新项目:
1npx create-react-app react-accordion-component
项目完成后,更改到目录:
1cd react-accordion-component
在新的终端卡或窗口中,使用 Create React App start script启动项目。
1npm start
如果项目未在浏览器窗口中打开,您可以通过访问 http://localhost:3000/ 打开它. 如果您正在从远程服务器运行,则地址将是 http://your_domain:3000
。
您的浏览器将加载 React 模板应用程序,作为 Create React App 的一部分:
您将构建一组全新的自定义组件,因此您需要从清除一些锅炉板代码开始,以便您可以有一个空的项目。
要开始,请在文本编辑器中打开src/App.js
。 这是注入到页面的根组件。 所有组件将从这里开始。 您可以找到有关App.js
的更多信息,请参阅How To Set Up a React Project with Create React App
(如何使用Create React App设置反应项目
(LINK0
))。
你會看到這樣的檔案:
1[label src/App.js]
2import logo from './logo.svg';
3import './App.css';
4
5function App() {
6 return (
7 <div className="App">
8 <header className="App-header">
9 <img src={logo} className="App-logo" alt="logo" />
10 <p>
11 Edit <code>src/App.js</code> and save to reload.
12 </p>
13 <a
14 className="App-link"
15 href="https://reactjs.org"
16 target="_blank"
17 rel="noopener noreferrer"
18 >
19 Learn React
20 </a>
21 </header>
22 </div>
23 );
24}
25
26export default App;
删除从
./logo.svg导入标识
行,然后更换返回
声明中的所有内容,以返回一组div
标签和一个h1
。
1[label src/App.js]
2import './App.css';
3
4function App() {
5 return (
6 <div>
7 <h1>Accordion Demo</h1>
8 </div>
9 );
10}
11
12export default App;
保存和退出文本编辑器。
最后,删除标志. 你不会在你的应用程序中使用它,你应该在工作时删除未使用的文件。
在终端窗口中,键入以下命令来删除标志:
1rm src/logo.svg
现在项目已经设置,您可以创建您的第一个组件。
步骤2 - 构建组件
我们将创建三个组成部分:
Accordion
:它将保留我们的部分组件,并管理哪些部分是开放的和关闭的.AccordionSection
:它将显示可点击的部分标题,部分内容,当该部分是开放的,并回报到Accordion
关于点击事件App
:组件将所有东西结合成一个工作示例!
Accordion
组件内的部分将简单地成为<div>
标签,它将收到一个标签
属性,用于AccordionSection
组件内的可点击区域。
让我们从创建我们最内在的组件开始,‘AccordionSection’:
1[label src/AccordionSection.js]
2import React from 'react';
3import PropTypes from 'prop-types';
4
5class AccordionSection extends React.Component {
6 static propTypes = {
7 children: PropTypes.instanceOf(Object).isRequired,
8 isOpen: PropTypes.bool.isRequired,
9 label: PropTypes.string.isRequired,
10 onClick: PropTypes.func.isRequired,
11 };
12
13 onClick = () => {
14 this.props.onClick(this.props.label);
15 };
16
17 render() {
18 const {
19 onClick,
20 props: { isOpen, label },
21 } = this;
22
23 return (
24 <div
25 style={{
26 background: isOpen ? '#fae042' : '#6db65b',
27 border: '1px solid #008f68',
28 padding: '5px 10px',
29 }}
30 >
31 <div onClick={onClick} style={{ cursor: 'pointer' }}>
32 {label}
33 <div style={{ float: 'right' }}>
34 {!isOpen && <span>▲</span>}
35 {isOpen && <span>▼</span>}
36 </div>
37 </div>
38 {isOpen && (
39 <div
40 style={{
41 background: '#6db65b',
42 border: '2px solid #008f68',
43 marginTop: 10,
44 padding: '10px 20px',
45 }}
46 >
47 {this.props.children}
48 </div>
49 )}
50 </div>
51 );
52 }
53}
54
55export default AccordionSection;
此组件将收到一个标签
属性,该属性将创建该部分的可点击标题。
主组件将处理哪些部分被打开或关闭的跟踪,并将状态作为布尔属性isOpen
返回到AccordionSection
。
「AccordionSection」的任何小组件只会显示,如果该部分已转移到打开,并且属性「isOpen」是真实的。
现在我们有部分组件,我们需要一个组件来容纳这些部分,并管理哪些部分已打开或关闭的状态:
1[label src/Accordion.js]
2import React from 'react';
3import PropTypes from 'prop-types';
4
5import AccordionSection from './AccordionSection';
6
7class Accordion extends React.Component {
8 static propTypes = {
9 children: PropTypes.instanceOf(Object).isRequired,
10 };
11
12 constructor(props) {
13 super(props);
14
15 const openSections = {};
16
17 this.state = { openSections };
18 }
19
20 onClick = label => {
21 const {
22 state: { openSections },
23 } = this;
24
25 const isOpen = !!openSections[label];
26
27 this.setState({
28 openSections: {
29 [label]: !isOpen
30 }
31 });
32 };
33
34 render() {
35 const {
36 onClick,
37 props: { children },
38 state: { openSections },
39 } = this;
40
41 return (
42 <div style={{ border: '2px solid #008f68' }}>
43 {children.map(child => (
44 <AccordionSection
45 isOpen={!!openSections[child.props.label]}
46 label={child.props.label}
47 onClick={onClick}
48 >
49 {child.props.children}
50 </AccordionSection>
51 ))}
52 </div>
53 );
54 }
55}
56
57export default Accordion;
我们的Accordion
组件将收到儿童节点,用于创建我们的互动AccordionSection
组件。
此组件追踪哪些部分已被转移打开,但只跟踪一次(目前)打开的单个部分。
创建了我们的Accordion
和AccordionSection
组件,我们现在可以创建我们的App
组件,并看到事情在行动!
对于我们的合奏演示,我们将创建一个合奏
,其中包括两个儿童组件,其中包含一些关于合奏者的事实:
1[label src/App.js]
2import Accordion from './Accordion';
3
4function App() {
5 return (
6 <div>
7 <h1>Accordion Demo</h1>
8 <Accordion>
9 <div label='Alligator Mississippiensis'>
10 <p>
11 <strong>Common Name:</strong> American Alligator
12 </p>
13 <p>
14 <strong>Distribution:</strong> Texas to North Carolina, US
15 </p>
16 <p>
17 <strong>Endangered Status:</strong> Currently Not Endangered
18 </p>
19 </div>
20 <div label='Alligator Sinensis'>
21 <p>
22 <strong>Common Name:</strong> Chinese Alligator
23 </p>
24 <p>
25 <strong>Distribution:</strong> Eastern China
26 </p>
27 <p>
28 <strong>Endangered Status:</strong> Critically Endangered
29 </p>
30 </div>
31 </Accordion>
32 </div>
33 );
34}
35
36export default App;
合并
包含两个部分,一旦点击打开,会显示一些关于不同种类的鱼的事实。
步骤 3 – 支持多个开放式协议
迄今为止我们创建的一切都是可用的,但有些有限,因为一次只能打开一个部分,并且每个部分默认情况下会崩溃。
为了增加对同时打开的多个部分的支持,我们将为Accordion
组件添加一个名为allowMultipleOpen
的属性,该组件将被用来告诉合并符是否应该允许多个部分打开。
当启用时,状态将切换个别键为 true/false,而不是完全重写状态与被交互的部分。
当我们在那里时,我们可以添加一些额外的逻辑来检查孩子节点的isOpen
属性。
1[label src/Accordion.js]
2import React from 'react';
3import PropTypes from 'prop-types';
4
5import AccordionSection from './AccordionSection';
6
7class Accordion extends React.Component {
8 static propTypes = {
9 allowMultipleOpen: PropTypes.bool,
10 children: PropTypes.instanceOf(Object).isRequired,
11 };
12
13 constructor(props) {
14 super(props);
15
16 const openSections = {};
17
18 this.props.children.forEach(child => {
19 if (child.props.isOpen) {
20 openSections[child.props.label] = true;
21 }
22 });
23
24 this.state = { openSections };
25 }
26
27 onClick = label => {
28 const {
29 props: { allowMultipleOpen },
30 state: { openSections },
31 } = this;
32
33 const isOpen = !!openSections[label];
34
35 if (allowMultipleOpen) {
36 this.setState({
37 openSections: {
38 ...openSections,
39 [label]: !isOpen
40 }
41 });
42 } else {
43 this.setState({
44 openSections: {
45 [label]: !isOpen
46 }
47 });
48 }
49 };
50
51 render() {
52 const {
53 onClick,
54 props: { children },
55 state: { openSections },
56 } = this;
57
58 return (
59 <div style={{ border: '2px solid #008f68' }}>
60 {children.map(child => (
61 <AccordionSection
62 isOpen={!!openSections[child.props.label]}
63 label={child.props.label}
64 onClick={onClick}
65 >
66 {child.props.children}
67 </AccordionSection>
68 ))}
69 </div>
70 );
71 }
72}
73
74export default Accordion;
随着我们的Accordion
准备接受新的参数,我们可以更新我们的App
组件,通过该属性,允许多个部分打开,以及标记第一个部分默认打开:
1[label src/App.js]
2import Accordion from './Accordion';
3
4function App() {
5 return (
6 <div>
7 <h1>Accordion Demo</h1>
8 <Accordion allowMultipleOpen>
9 <div label='Alligator Mississippiensis' isOpen>
10 <p>
11 <strong>Common Name:</strong> American Alligator
12 </p>
13 <p>
14 <strong>Distribution:</strong> Texas to North Carolina, US
15 </p>
16 <p>
17 <strong>Endangered Status:</strong> Currently Not Endangered
18 </p>
19 </div>
20 <div label='Alligator Sinensis'>
21 <p>
22 <strong>Common Name:</strong> Chinese Alligator
23 </p>
24 <p>
25 <strong>Distribution:</strong> Eastern China
26 </p>
27 <p>
28 <strong>Endangered Status:</strong> Critically Endangered
29 </p>
30 </div>
31 </Accordion>
32 </div>
33 );
34}
35
36export default App;
在那里,你有它,一个可重复使用的和谐组件,可以帮助你控制不合规的内容。
结论
在本文中,您创建了一个简单的可重复使用的合适件组件,其中有可以转移开启和关闭的部分。
继续学习,将这些和谐结合起来,以满足最复杂的场景。
您可以在 CodeSandbox上找到这篇文章中的工作演示文稿和代码。