React组件树关闭先前打开的父节点

时间:2018-05-09 06:07:44

标签: reactjs

我创建了一个用于导航的反应组件树。 您可以在下面的代码中看到它。

React Component Tree

    let navConfigData = {
  isDashboardVisible: true,
  tierOneLinks: [
    {
      name: "First Page",
      iconName: "star",
      iconAbbreviation: "FP",
      tierTwoItems: [
        {
          name: "Tier 2 Page",
          iconName: "star",
          iconAbbreviation: "FP",
          tierThreeItems: [
            {
              name: "Tier 3 Page",
              iconName: "star",
              iconAbbreviation: "FP",
              path: "#"
            }
          ]
        },
        {
          name: "Tier 2 sec Page",
          iconName: "star",
          iconAbbreviation: "FP",
          path: "#"
        }
      ]
    },
    {
      name: "Second Page",
      iconName: "",
      iconAbbreviation: "SP",
      path: "#"
    },
    {
      name: "Third Page",
      iconAbbreviation: "TP",
      path: "#",
      tierTwoItems: [
        {
          name: "Tier 2 Page",
          iconName: "star",
          iconAbbreviation: "FP",
          tierThreeItems: [
            {
              name: "Tier 3 Page",
              iconName: "star",
              iconAbbreviation: "FP",
              path: "#"
            }
          ]
        },
        {
          name: "Tier 2 sec Page",
          iconName: "star",
          iconAbbreviation: "FP",
          path: "#"
        }
      ]
    },
    {
      name: "Fourth Page",
      iconName: "send",
      iconAbbreviation: "FO",
      path: "#"
    }
  ],
  supportLinks: [
    {
      name: "First Support Page",
      iconName: "settings",
      iconAbbreviation: "FI",
      path: "#"
    },
    {
      name: "Second Support Page",
      iconName: "security",
      iconAbbreviation: "SE",
      path: "#"
    },
    {
      name: "Third Support Page",
      iconName: "help",
      iconAbbreviation: "TH",
      path: "#"
    }
  ]
};


class NavigationDrawerTierThree extends React.Component {

  onClick = evt => {
    this.props.onSelect(this.props.tierThree.name);
  };


  render() {
    const { tierThree, selectedTierThreeLink } = this.props;
debugger;
    return (
        <a
          className="mdc-list-item my-nav-drawer__tier-three"          
          onClick={this.onClick}
        >
          <span className="my-nav-drawer__tier-two-label">
            {tierThree.name}
          </span>
        </a>
    );
  }
}


 class NavigationDrawerTierTwo extends React.Component {
  // static propTypes = {
  //   tierTwo: object.isRequired,
  //   showNavIcon: bool,
  //   onSelect: func.isRequired,
  //   selectedTierTwoLink: string.isRequired
  // };

  state = { tierTwoIsExpanded: false };

  onClick = evt => {
    debugger;
    this.props.onSelect(this.props.tierTwo.name, "tier2");
    const { tierTwoIsExpanded } = this.state;
    this.setState({ tierTwoIsExpanded: !tierTwoIsExpanded });
  };

  getArrowIcon = () => {
    return this.state.tierTwoIsExpanded ? (
      <span class="material-icons cdk-nav-drawer__tier-two-icon">></span>
    ) : (
      <span class="material-icons cdk-nav-drawer__tier-two-icon">
        ^
      </span>
    );
  };

  getAnchorClassBasedOnTier = () => {
      return this.props.showNavIcon
        ? "cdk-nav-drawer__tier-two"
        : "cdk-nav-drawer__tier-three";
  };

  getLabelClassBasedOnTier = () => {
      return this.props.showNavIcon
        ? "cdk-nav-drawer__tier-two-label"
        : "cdk-nav-drawer__tier-three-label";
  };

  render() {
    const { tierTwo, showNavIcon, selectedTierTwoLink } = this.props;
    const { tierTwoIsExpanded } = this.state;

debugger;
    return (
      <div>
        <a
          className="mdc-list-item my-nav-drawer__tier-two"   
          onClick={this.onClick}
          >
          {showNavIcon && this.getArrowIcon()}
          <span className="my-nav-drawer__tier-two-label">
            {tierTwo.name}
          </span>
        </a>
        {tierTwoIsExpanded && this.props.children}
        </div>

    );
  }
}

class NavigationDrawerTierOneAnchor extends React.Component{
  //   static propTypes = {
  //   tierOne: object.isRequired,
  //   onSelect: func.isRequired,
  //   selectedTierOneLink: string.isRequired
  // };

 // state = { tierIsExpanded: false };

onClick = evt => {
    this.props.onSelect(this.props.tierOne.name, "tier1");
    // const { tierIsExpanded } = this.state;
    // this.setState({ tierIsExpanded: !tierIsExpanded });
  };

render(){
    const { tierOne, selectedTierOneLink, expanded } = this.props;
  return(
    <div>
        <a
          className="mdc-list-item my-nav-drawer__tier-one"
          href={tierOne.path}
          onClick={this.onClick}
          ref={a => {
            this.anchor = a;
          }}
        >
       <span className="cdk-nav-drawer__tier-one-label">
            {tierOne.name}
          </span>
      </a>
        {expanded && this.props.children}
      </div>
  );
}

}
class NavigationDrawerAppTiers extends React.Component {
  // static propTypes = {
  //   tierOneArray: array.isRequired,
  //   onToggleExpand: func.isRequired,
  //   onSelect: func.isRequired,
  //   selectedTierOneLink: string.isRequired,
  //   selectedTierTwoLink: string.isRequired,
  //   selectedTierThreeLink: string.isRequired,
  //   expandedTierOneName: string.isRequired
  // };

  render(){
        const { tierOneArray, onSelect, selectedTierOneLink, selectedTierTwoLink, selectedTierThreeLink, expandedTierOneName } = this.props;
        return (
          <div className="mdc-drawer__content my-nav-drawer__app-tiers">
            <nav className="mdc-list">
          {tierOneArray.map((tierOneLink, index) => (
            <NavigationDrawerTierOneAnchor
              tierOne={tierOneLink}
              onSelect={onSelect}
              key={index}
              expanded={tierOneLink.name === this.props.expandedTierOneName}
              selectedTierOneLink={selectedTierOneLink}
            >
              {(tierOneLink.tierTwoItems || []).map((tierTwoItem, index) => (
                <NavigationDrawerTierTwo
                  tierTwo={tierTwoItem}
                  onSelect={onSelect}
                  selectedTierTwoLink={selectedTierTwoLink}
                  showNavIcon={
                    (tierTwoItem.tierThreeItems &&
                      tierTwoItem.tierThreeItems.length > 0) ||
                    false
                  }
                >
                  {(tierTwoItem.tierThreeItems || []).map(
                    (tierThreeItem, index) => (
                      <NavigationDrawerTierThree
                        tierThree={tierThreeItem}
                        onSelect={onSelect}
                        selectedTierThreeLink={selectedTierThreeLink}
                        />
                    )
                  )}
                </NavigationDrawerTierTwo>
              ))}
            </NavigationDrawerTierOneAnchor>
          ))}
        </nav>
          </div>
        );
  }

}


class NavigationDrawer extends React.Component {
 // static propTypes = {
 //    navConfig: object.isRequired
 //  };

state = {
    isDrawerCollapsed: false,
    selectedTierOneLink: "",
    selectedTierTwoLink: "",
    selectedTierThreeLink: "",
    expandedTierOneName: ""
  };

onSelect = (selectedLinkName, selectedTier) => {
    if(selectedTier == "tier1"){
      if (selectedLinkName === this.state.selectedTierOneLink) {
        // User clicked on the same link again
        this.setState(state => ({
          expandedTierOneName: state.expandedTierOneName?"":selectedLinkName
        }))
      } else {
        this.setState(state=>({
          expandedTierOneName:selectedLinkName
        }))
      }
      this.setState(state => ({ selectedTierOneLink: selectedLinkName }));
      this.setState(state => ({ selectedTierTwoLink: "" }));
    } else if (selectedTier == "tier2"){
      this.setState(state => ({ selectedTierTwoLink: selectedLinkName }));
      this.setState(state => ({ selectedTierThreeLink: "" }));
    } else {
      this.setState(state => ({ selectedTierThreeLink: selectedLinkName }));
      this.setState(state => ({ selectedTierTwoLink: "" }));

    }
  };

    render(){
          const { navConfig } = this.props;
        return(
        <nav className="mdc-drawer mdc-drawer--permanent mdc-typography my-nav-drawer">
            <div className="my-nav-drawer__links">
              <NavigationDrawerAppTiers
              tierOneArray={navConfig.tierOneLinks}
              onSelect={this.onSelect}
              selectedTierOneLink={this.state.selectedTierOneLink}
              selectedTierTwoLink={this.state.selectedTierTwoLink}
              selectedTierThreeLink={this.state.selectedTierThreeLink}
              expandedTierOneName={this.state.expandedTierOneName}
            />
            </div>
        </nav>
        );
    }

}




React.render(
    <NavigationDrawer navConfig={navConfigData}/>, 
    document.body
);

该组件最多可达三个级别,我不希望它目前通过递归实现。

我正在寻找一种行为,在从另一个父树中选择任何子节点后关闭先前打开的父树节点。

要从Codepen示例中详细解释,我需要有关以下方案的帮助。

目前,如果未选择子项,则只能切换一个父节点。

我需要帮助才能实现以下方案。

  1. 点击第一页上的任何子项, 现在点击第三页不应该折叠第一页(因为从第一页中选择了一个项目),当第三页中的任何子项被选中时,第一页应该折叠。
  2. 如果从第三页中没有选择子项,则再次单击第三页,则应折叠所有打开的父节点(第一页和第三页)。

    有人可以帮我修改码头。

    在代码抛出下,未定义initialState

        class NavigationDrawer extends React.Component {
      static propTypes = {
         navConfig: object.isRequired
       };
    
      initialState = this.props.navConfig.tierOneLinks.reduce((acc, { name }) => {
      acc[name] = false;
      return acc;
    }, {});
    
    state = {
         expanded: initialState,
        isDrawerCollapsed: false,
        selectedTierOneLink: "",
        selectedTierTwoLink: "",
        selectedTierThreeLink: "",
        expandedTierOneName: ""
      };
    
    onSelect = (selectedLinkName, selectedTier) => {
        if(selectedTier == "tier1"){
          if (selectedLinkName === this.state.selectedTierOneLink) {
            // User clicked on the same link again
            this.setState(state => ({
              expandedTierOneName: state.expandedTierOneName?"":selectedLinkName
            }))
          } else {
            this.setState(state=>({
              expandedTierOneName:selectedLinkName
            }))
          }
          this.setState(state => ({ selectedTierOneLink: selectedLinkName }));
          this.setState(state => ({ selectedTierTwoLink: "" }));
        } else if (selectedTier == "tier2"){
          this.setState(state => ({ selectedTierTwoLink: selectedLinkName }));
          this.setState(state => ({ selectedTierThreeLink: "" }));
        } else {
          this.setState(state => ({ selectedTierThreeLink: selectedLinkName }));
          this.setState(state => ({ selectedTierTwoLink: "" }));
    
        }
      };
    
        render(){
              const { navConfig } = this.props;
    
            return(
            <nav className="mdc-drawer mdc-drawer--permanent mdc-typography my-nav-drawer">
                <div className="my-nav-drawer__links">
                  <NavigationDrawerAppTiers
                  tierOneArray={navConfig.tierOneLinks}
                  onSelect={this.onSelect}
                  selectedTierOneLink={this.state.selectedTierOneLink}
                  selectedTierTwoLink={this.state.selectedTierTwoLink}
                  selectedTierThreeLink={this.state.selectedTierThreeLink}
                  expandedTierOneName={this.state.expandedTierOneName}
                />
                </div>
            </nav>
            );
        }
    
    }
    

0 个答案:

没有答案