【问题标题】:How to create collapse expand list in react如何在反应中创建折叠展开列表
【发布时间】:2020-01-22 05:43:30
【问题描述】:

我尝试使用以下条件在React (v 16.5) 中创建折叠和展开侧边菜单 -

页面加载时第一个项目(通告)将在展开视图中。任何一个项目都可以一次展开,例如,如果用户单击第二个项目(规格),第一个项目将折叠。我还想要一些 CSS 动画在折叠/展开事务期间,比如平滑地向下/向上每个项目的主体部分并更改箭头图标。我的方法是动态添加/删除每个项目 (sidebar-nav-menu-item) 上的 CSS 类,例如 -

sidebar-nav-menu-item item-active

因此,当一个项目处于展开视图时,它应该像上面的类,并在其处于折叠视图时删除 item-active。默认情况下,当 item 处于折叠模式时,body divs (sidebar-nav-menu-item-body) 应该通过 CSS 隐藏。

import React, { Component } from 'react';

className SidebarNavs extends React.Component{
    constructor(props) {
       super(props);
    }

    render() {
        return(
            <div className="sidebar-nav">
                <div className="sidebar-nav-menu">

                    <div className="sidebar-nav-menu-item" data-id="circulars">
                        <div className="sidebar-nav-menu-item-head" onClick={this.handleExpandCollaps}>
                            <div className="sidebar-nav-menu-item-head-title">Circulars</div>
                            <div className="sidebar-nav-menu-item-head-help">
                                <button type="button" className="btn-help" onClick={this.moreInfoClick}>View more info</button>
                            </div>
                            <div className="sidebar-nav-menu-item-head-icon">
                                <i className="fa fa-caret-down" aria-hidden="true"></i>
                            </div>
                        </div>
                        <div className="sidebar-nav-menu-item-body">BODY CONTENT HERE</div>
                    </div>

                    <div className="sidebar-nav-menu-item" data-id="specifications">
                        <div className="sidebar-nav-menu-item-head" onClick={this.handleExpandCollaps}>
                            <div className="sidebar-nav-menu-item-head-title">Specifications</div>
                            <div className="sidebar-nav-menu-item-head-help">
                                <button type="button" className="btn-help" onClick={this.moreInfoClick}>View more info</button>
                            </div>
                            <div className="sidebar-nav-menu-item-head-icon">
                                <i className="fa fa-caret-down" aria-hidden="true"></i>
                            </div>
                        </div>
                        <div className="sidebar-nav-menu-item-body">BODY CONTENT HERE</div>
                    </div>


                    <div className="sidebar-nav-menu-item"  data-id="wo">
                        <div className="sidebar-nav-menu-item-head" onClick={this.handleExpandCollaps}>
                            <div className="sidebar-nav-menu-item-head-title">Work Orders</div>
                            <div className="sidebar-nav-menu-item-head-help">
                                <button type="button" className="btn-help" onClick={this.moreInfoClick}>View more info</button>
                            </div>
                            <div className="sidebar-nav-menu-item-head-icon">
                                <i className="fa fa-caret-down" aria-hidden="true"></i>
                            </div>
                        </div>
                        <div className="sidebar-nav-menu-item-body">BODY CONTENT HERE</div>
                    </div>

                </div>
            </div>
        )
    }
}

export default SidebarNavs;

CSS:

.sidebar-nav-menu-item{
   display:block;
}
.sidebar-nav-menu-item-body{
   display:none;
}
.sidebar-nav-menu-item.item-active .sidebar-nav-menu-item-body{
   display:block;
}

【问题讨论】:

  • 那太好了,因为我需要每个部分的正文部分都应该平滑显示,并且标题上的图标,它应该在展开时向上箭头。
  • fa-caret-down 应该是 fa-caret-up

标签: javascript reactjs


【解决方案1】:

您应该使用状态变量来显示您的可折叠项目处于活动/非活动状态。

我稍微修改了您的代码以适应您的要求。

class App extends Component {
  constructor() {
    super();
    this.state = {
        activeCollapse: 'circulars'
    };
  }

  handleExpandCollaps = (name) => {
    if (this.state.activeCollapse === name) {
        this.setState({ activeCollapse: '' })
    } else {
        this.setState({ activeCollapse: name })
    }
  }

  moreInfoClick = (e) => {
    e.stopPropagation();
    console.log("clicked");
  }
  render() {
    return (
      <div>
        <div className="sidebar-nav">
          <div className="sidebar-nav-menu">

            <div className={`sidebar-nav-menu-item ${this.state.activeCollapse === "circulars" ? 'item-active' : ''}`} onClick={() => this.handleExpandCollaps("circulars")} data-id="circulars" >
              <div className="sidebar-nav-menu-item-head">
                <span className="sidebar-nav-menu-item-head-title">Circulars</span>
                <span className="sidebar-nav-menu-item-head-help">
                  <button type="button" className="btn-help" onClick={this.moreInfoClick}>View more info</button>
                </span>
              </div>
              <div className="sidebar-nav-menu-item-body">BODY CONTENT HERE</div>
            </div>

            <div className={`sidebar-nav-menu-item ${this.state.activeCollapse === "specifications" ? 'item-active' : ''}`} onClick={() => this.handleExpandCollaps("specifications")} data-id="specifications">
              <div className="sidebar-nav-menu-item-head">
                <span className="sidebar-nav-menu-item-head-title">Specifications</span>
                <span className="sidebar-nav-menu-item-head-help">
                  <button type="button" className="btn-help" onClick={this.moreInfoClick}>View more info</button>
                </span>
              </div>
              <div className="sidebar-nav-menu-item-body">BODY CONTENT HERE</div>
            </div>


            <div className={`sidebar-nav-menu-item ${this.state.activeCollapse === "wo" ? 'item-active' : ''}`} onClick={() => this.handleExpandCollaps("wo")} data-id="wo">
              <div className="sidebar-nav-menu-item-head">
                <span className="sidebar-nav-menu-item-head-title">Work Orders</span>
                <span className="sidebar-nav-menu-item-head-help">
                  <button type="button" className="btn-help" onClick={this.moreInfoClick}>View more info</button>
                </span>
              </div>
              <div className="sidebar-nav-menu-item-body">BODY CONTENT HERE</div>
            </div>

          </div>
        </div>
      </div>
    );
  }
}

注意:我使用CSS 代替font-awesome 图标。希望你加了font-awesome

Demo

【讨论】:

    【解决方案2】:

    为此,我会使用React.useState,因为它是一个小状态来控制和动画我会使用 CSS:

    组件看起来像这样:

    function SidebarNavs() {
      const [activeItem, setActiveItem] = React.useState(1);
    
      return (
        <div className="sidebar-nav">
          <div className="sidebar-nav-menu">
            <SidebarItem
              title="Circulars"
              setActiveItem={setActiveItem}
              index={1}
              activeItem={activeItem}
            >
              Sidebar Content Here
            </SidebarItem>
    
            <SidebarItem
              title="Specifications"
              setActiveItem={setActiveItem}
              index={2}
              activeItem={activeItem}
            >
              Sidebar Content Here
            </SidebarItem>
    
            <SidebarItem
              title="Specifications"
              setActiveItem={setActiveItem}
              index={3}
              activeItem={activeItem}
            >
              Work Orders
            </SidebarItem>
          </div>
        </div>
      );
    }
    
    function SidebarItem({ title, children, setActiveItem, activeItem, index }) {
      const expanded = activeItem === index;
      const cls = "sidebar-nav-menu-item " + (expanded ? "item-active" : "");
      return (
        <div className={cls}>
          <div className="sidebar-nav-menu-item-head">
            <div className="sidebar-nav-menu-item-head-title">{title}</div>
            <div className="sidebar-nav-menu-item-head-help">
              <button
                type="button"
                className="btn-help"
                onClick={() => setActiveItem(index)}
              >
                View more info
              </button>
            </div>
            <div className="sidebar-nav-menu-item-head-icon">
              <i className="fa fa-caret-down" aria-hidden="true" />
            </div>
          </div>
          <div className="sidebar-nav-menu-item-body">{children}</div>
        </div>
      );
    }
    

    CSS 看起来像这样:

    .sidebar-nav-menu-item {
      border: 1px solid #CCC;
      margin-bottom: 20px;
    }
    .sidebar-nav-menu-item .sidebar-nav-menu-item-body {
      overflow: hidden;
      max-height: 0;
      transition: all linear 0.5s;
    }
    
    .sidebar-nav-menu-item.item-active .sidebar-nav-menu-item-body {
      max-height: 100px;
      transition: all linear 0.5s 0.3s;
    }
    
    

    【讨论】:

    • 感谢 Bruno,但我使用的是 16.5 版本的反应,但我无法使用 16.8 版本的 UseState
    • 换句话说,是否可以不创建子组件 ??
    • 我也想在 sidebar-nav-menu-item elm 上触发点击事件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-18
    • 2015-07-18
    相关资源
    最近更新 更多