我是React.js的新手,我正在通过将使用javascript制作的网站转换为React.js应用程序来学习。但是,我在复制导航栏上的下拉菜单功能时遇到麻烦。
每个部分均由具有onClick的div组成,该onClick可以通过更改overflow
和height
css设置垂直扩展其内容以使其可见。但是,有一个陷阱:一次只能扩展一个下拉菜单。我能够在常规的JS网站中做到这一点,但我想在React中使用组件之间的父子关系和同级关系在新版本中获得相同的效果。
使用onClick事件,应打开该栏的一个标签,如果展开了其他标签,则将其关闭。
我尝试将解决方案中的信息用于this question,但它不是类组件形式的,而是处理输入而不是div。此外,与此相关的大多数搜索结果仅涉及普通js,而不涉及React.js。
起初,我尝试将状态保留在父组件中,但是它们的异步特性使它很难在正确的时间更新它们。
在这里,我删除了网站的其他不相关部分,并提供了我的问题的副本。
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import Tab from './Tab';
import './index.css';
class TabBar extends React.Component {
constructor() {
super();
this.state = {
//currently no states
}
}
render() {
return (
<div className="tab_bar">
<Tab name="Tab 1" />
<Tab name="Tab 2" />
<Tab name="Tab 3" />
</div>
)
}
}
class Main extends React.Component {
render() {
return (
<TabBar />
)
}
}
ReactDOM.render(<Main />, document.getElementById('root'));
Tab.js:
import React from 'react';
class TabHeader extends React.Component {
constructor() {
super();
}
render() {
return (
<div className="tab_header" onClick={this.props.onClick}>
<h3>{this.props.name}</h3>
</div>
)
}
}
class Tab extends React.Component {
constructor(props) {
super(props);
this.state = {
height: "7vh",
overflow: "hidden"
}
this.changeTabHeight = this.changeTabHeight.bind(this);
}
changeTabHeight() {
if (this.state.height === "7vh") {
this.setState({
height: "20vh",
overflow: "unset"
});
} else {
this.setState({
height: "7vh",
overflow: "hidden"
});
}
}
render() {
return (
<div className="tab_container" style={{overflow: this.state.overflow, height: this.state.height}}>
<TabHeader name={this.props.name} onClick={this.changeTabHeight} />
<div className="tab">
<p>This is the tab content.</p>
</div>
</div>
)
}
}
export default Tab;
index.css:
.body, .root {
width: 100%;
height: 100%;
}
.tab_bar {
width: 100%;
height: 10%;
display: flex;
}
.tab_container{
height: 7vh;
margin: 0;
display: inline-block;
background-color: #82d86c;
border-left: 1px solid #99ff7f;
-webkit-transition: height 0.5s;
transition: height 0.5s;
overflow: hidden;
}
.tab_header {
display: flex;
align-items: center;
vertical-align: middle;
height: 7vh;
text-align: center;
background-color: #99ff7f;
}
.tab_header h3 {
margin: 0;
}
.tab {
margin: 0;
padding: 5px;
}
预期结果: 单击导航栏上的选项卡时,它将展开并在其下方显示信息。再次单击它可以将选项卡还原到其原始高度并隐藏。当前打开一个选项卡时,单击它会关闭旧的选项卡并展开新的选项卡。
实际结果: 目前,它们的扩张如预期的那样,但是它们还没有相互关闭的方法。它需要父级中的结构来跟踪下拉列表。
答案 0 :(得分:1)
当前存在的问题是,您直接在Tab
内部的子组件TabBar
中处理状态。
按您期望的那样采用模块化方式。
index.js :我们可以通过创建一个Tab数组并遍历此选项卡来对其进行改进
import React from "react";
import ReactDOM from "react-dom";
import Tab from "./Tab";
import "./index.css";
class TabBar extends React.Component {
constructor() {
super();
this.state = {
selectedTab: null,
};
this.onSelectTab = this.onSelectTab.bind(this);
}
onSelectTab(tabIndex) {
// In case the user clicks again on the tab, unselect it
const selectedTab = this.state.selectedTab === tabIndex ? false : tabIndex;
this.setState({ selectedTab });
}
render() {
return (
<div className="tab_bar">
<Tab
name="Tab 1"
isSelected={this.state.selectedTab === 0}
onClickTab={() => this.onSelectTab(0)}
/>
<Tab
name="Tab 2"
isSelected={this.state.selectedTab === 1}
onClickTab={() => this.onSelectTab(1)}
/>
<Tab
name="Tab 3"
isSelected={this.state.selectedTab === 2}
onClickTab={() => this.onSelectTab(2)}
/>
</div>
);
}
}
class Main extends React.Component {
render() {
return <TabBar />;
}
}
ReactDOM.render(<Main />, document.getElementById("root"));
Tab.js :请记住,拥有功能组件而不带状态是更好的方法。
import React from "react";
class TabHeader extends React.Component {
constructor() {
super();
}
render() {
return (
<div className="tab_header" onClick={this.props.onClickTab}>
<h3>{this.props.name}</h3>
</div>
);
}
}
class Tab extends React.Component {
constructor(props) {
super(props);
}
render() {
// Moved the style in the CSS rather than in function + state
// The !!this.props.isSelected allow to always return false / true response
return (
<div className={ `tab_container is-selected-${!!this.props.isSelected}`}>
<TabHeader name={this.props.name} onClickTab={this.props.onClickTab} />
<div className="tab">
<p>This is the tab content.</p>
</div>
</div>
);
}
}
export default Tab;
index.css :添加这两个类,因为最好在CSS中使用样式,而不是直接在组件内部使用
.is-selected-true {
height: "20vh",
overflow: "unset"
}
.is-selected-false {
height: "7vh",
overflow: "hidden"
}