【问题标题】:Close previous sub-menu and show clicked sub-menu with single click in ReactJS在 ReactJS 中单击关闭上一个子菜单并显示单击的子菜单
【发布时间】:2021-05-20 15:40:33
【问题描述】:

我将下面的代码用于侧导航菜单。每个导航项都有子导航项。

当前行为

  • 子导航项确实会在单击时打开,但是当单击下一个导航标题时,它会关闭当前子菜单,并且需要第二次单击才能打开所需的子菜单。这意味着用户必须单击两次才能打开所需子菜单的子菜单,因为单击一次关闭上一个子菜单,然后单击 2 打开所需的子菜单。

  • 点击子菜单项后,整个子菜单关闭

要求的行为

  • 默认情况下,网络子菜单应打开,除非用户单击另一个导航标题。
  • 当用户单击其中一个子菜单项时,单击的标题和子菜单应保持打开状态。
  • 子菜单应通过单击打开并关闭其他打开的子菜单。

代码

import React, { useState } from "react";
import { NavLink } from "react-router-dom";
import userImage from "../../global/assets/img/avatar.png";
import { RiSettings2Line } from "react-icons/ri";

export const AppSideNav = () => {
  const [open, setOpen] = useState("networking");
  const navDetails = [
    {
      navId: 1,
      navHead: "Networking",
      subNavItems: ["item 1", "item 2"],
      navLink: "networking",
    },
    {
      navId: 2,
      navHead: "Trading",
      subNavItems: ["item 1", "item 2"],
      navLink: "trading",
    },
  ];

  const toggle = (id) => setOpen(open === id ? undefined : id);

  const subNavFunction = (navLink, subNavVal) => {
    return `/${navLink}/` + `${subNavVal.toLowerCase()}`;
  };

  return (
    <div className="AppSideNavContentContainer">
      <div className="AppSideNavContentTop">
        <div className="AppSideNavContentTopWrapper">
          <div className="AppSideNavUserPicContainer">
            <div className="AppSideNavUserPic">
              <img src={userImage} alt="user-avatar" className="UserAvatar" />
            </div>
          </div>
          <div className="AppSideNavUserNameContainer">
            <div className="AppSideNavUserName">
              <div className="AppSideNavUserNameText"> Username</div>
            </div>
            <div className="AppSideNavUserWalletId"> 0x99343</div>
          </div>
          <div className="AppSideNavUserDdIconContainer">
            <button className="AppSideNavUserDdIconContainerWrapper">
              <div className="AppSideNavUserDdIconInner">
                <RiSettings2Line />
              </div>
            </button>
          </div>
        </div>
      </div>
      <div className="AppSideNavContentBody">
        <div className="SideAppNavBodySection">
          <div className="SideAppNavLinkWrapper">
            <ul className="SideNavHomeList">
              {navDetails.map((items) => (
                <NavLink
                  to={
                    items.navHead === "Networking"
                      ? "/networking"
                      : items.navHead === "Trading"
                      ? "/trading"
                      : items.navHead === "Staking & Mining"
                      ? "/staking"
                      : items.navHead === "Smart Wallet"
                      ? "/wallet"
                      : items.navHead === "IDO List"
                      ? "ido"
                      : ""
                  }
                  className="SideNavLinkContainer"
                >
                  <div
                    className="OverFlowHidden"
                    onClick={() => toggle(items.navId)}
                  >
                    <div className="SideNavLinkItemContainer">
                      <div className="SideNavLinkItemContainerWrapper">
                        <div className="SideNavLinkItemContainerInner">
                          <div className="SideNavLinkItemContainerInnerWrapper">
                            <span
                              className={
                                items.navHead === "Networking"
                                  ? "SideNavLinkIcon PortfolioIcon"
                                  : items.navHead === "Trading"
                                  ? "SideNavLinkIcon TradingIcon"
                                  : items.navHead === "Staking & Mining"
                                  ? "SideNavLinkIcon StakingIcon"
                                  : items.navHead === "Smart Wallet"
                                  ? "SideNavLinkIcon WalletIcon"
                                  : "SideNavLinkIcon LaunchIcon"
                              }
                            >
                              {" "}
                            </span>
                          </div>
                        </div>
                        <span className="SideNavLinkText">
                          {" "}
                          {items.navHead}{" "}
                        </span>
                      </div>
                      {open === items.navId && (
                        <div className="SideNavLinkSubItemsContainer">
                          <div className="SideNavLinkSubItemsWrapper">
                            <div>
                              <span className="SideNavLinkSubItem">
                                {" "}
                                {items.subNavItems.map((navItem) => (
                                  <NavLink
                                    to={subNavFunction(items.navLink, navItem)}
                                  >
                                    <div className="SideNavLinkSubItemInner">
                                      <span className="SideNavLinkSubItem">
                                        {" "}
                                        {navItem}
                                      </span>
                                    </div>
                                  </NavLink>
                                ))}
                              </span>
                            </div>
                          </div>
                        </div>
                      )}
                    </div>
                  </div>
                </NavLink>
              ))}
            </ul>
          </div>
        </div>
      </div>
    </div>
  );
};

【问题讨论】:

  • 很难想象你需要什么,你能设置一个codesandbox吗?
  • 嗨@diedu,我已经设置了代码沙箱codesandbox.io/s/shy-wave-ru5ce?file=/src/App.js。如您所见,MENU 1 和 MENU 2 的子菜单项是隐藏的,我需要的是 MENU 1 子项在用户访问页面时默认打开。但是当单击菜单 2 时,在单个上一个菜单中,子项应关闭并打开 CLICKED 菜单的子项。例如,当用户单击菜单 2 时,菜单 1 子项应关闭,而菜单 2 子项应通过相同的单击打开。
  • 呵呵,我没有得到你想要的东西,我看到你当前版本的代码框可以满足你的要求codesandbox.io/s/icy-surf-w1p8g?file=/src/App.js,或者你需要手风琴之类的东西吗?

标签: reactjs


【解决方案1】:

根据您的代码沙箱,您需要做两件事:

  1. 使用默认导航 ID 初始化打开:
const [open, setOpen] = useState(() => navDetails[0].navId);

您可以将初始条件更改为任何内容。如果您希望您的数据控制默认打开的内容,您可以将 isDefault: true 添加到必须默认打开的项目并更新上面的状态初始化程序。

  1. 根据在切换中选择的 ID 更改打开:
  const toggle = (id) => setOpen(open === id ? undefined : id);

【讨论】:

  • 我尝试了代码,它在没有导航链接的情况下工作,我在这里更新了代码ru5ce.csb.app 你能检查为什么导航链接会改变行为并需要双击打开子菜单这里的密码箱ru5ce.csb.app
【解决方案2】:

onClick={() =&gt; toggle(items.navId)} 移动到您的导航标题而不是容器。

import React, { useState } from "react";
import "./nav.css";

export const AppSideNav = () => {
  const navDetails = [
    {
      navId: 1,
      navHead: "menu 1",
      subNavItems: ["submenu 1", "submenu 2"],
      to: "menu1"
    },
    {
      navId: 2,
      navHead: "menu 2",
      subNavItems: ["submenu 1", "submenu 2"],
      to: "menu2"
    }
  ];
  const [open, setOpen] = useState(false);

  const toggle = (id) => setOpen(open === id ? undefined : id);

  return (
    <div className="AppSideNavContentContainer">
      <div className="AppSideNavContentBody">
        <div className="SideAppNavBodySection">
          <div className="SideAppNavLinkWrapper">
            <ul className="SideNavHomeList">
              {navDetails.map((items) => (
                <div className="OverFlowHidden">
                  <div className="SideNavLinkItemContainer">
                    <div
                      onClick={() => toggle(items.navId)} //add you click handler here 
                      className="SideNavLinkItemContainerWrapper"
                    >
                      <div className="SideNavLinkItemContainerInner">
                        <div className="SideNavLinkItemContainerInnerWrapper">
                          <span
                            className={
                              items.navHead === "Networking"
                                ? "SideNavLinkIcon PortfolioIcon"
                                : items.navHead === "Trading"
                                ? "SideNavLinkIcon TradingIcon"
                                : items.navHead === "Staking & Mining"
                                ? "SideNavLinkIcon StakingIcon"
                                : items.navHead === "Smart Wallet"
                                ? "SideNavLinkIcon WalletIcon"
                                : "SideNavLinkIcon LaunchIcon"
                            }
                          >
                            {" "}
                          </span>
                        </div>
                      </div>
                      <span className="SideNavLinkText"> {items.navHead} </span>
                    </div>
                    {items.subNavItems.map((navSubMenu) => (
                      <div className="SideNavLinkSubItemsWrapper">
                        <div className="SideNavLinkSubItemsWrapper">
                          <div
                            className={
                              open === items.navId
                                ? "SideNavLinkSubItemInner"
                                : "DisplayNone"
                            }
                          >
                            <span className="SideNavLinkSubItem">
                              {navSubMenu}
                            </span>
                          </div>
                        </div>
                      </div>
                    ))}
                  </div>
                </div>
              ))}
            </ul>
          </div>
        </div>
      </div>
    </div>
  );
};

【讨论】:

  • 感谢您的回复,我尝试了代码,它工作正常,但没有导航链接。一旦我添加了导航链接,它就会回到相同的行为并需要双击才能打开。我在这里更新了代码沙箱ru5ce.csb.app
  • 你应该打开一个新问题,我们解决了原来的问题。
【解决方案3】:

使用 NavLink 彻底解决您的问题。下面提到了修复。

  1. NavLink 仅用于导航目的。所以我只用它来包装必要的元素。这将防止不必要的状态更新。
  2. 您的代码始终更新navId,而不是navLink。所以我用 Networking navId 初始化状态。
  3. 删除setOpen 方法中的条件。

SideNav.js

import { useState } from "react";
import { NavLink } from "react-router-dom";

export const SideNav = () => {
  const [open, setOpen] = useState(1);
  const navDetails = [
    {
      navId: 1,
      navHead: "Networking",
      subNavItems: ["item 1", "item 2"],
      navLink: "networking",
    },
    {
      navId: 2,
      navHead: "Trading",
      subNavItems: ["item 1", "item 2"],
      navLink: "trading",
    },
  ];

  const toggle = (id) => setOpen(id);

  const subNavFunction = (navLink, subNavVal) => {
    return `/${navLink}/${subNavVal.toLowerCase()}`;
  };

  return (
    <div className="AppSideNavContentContainer">
      <div className="AppSideNavContentBody">
        <div className="SideAppNavBodySection">
          <div className="SideAppNavLinkWrapper">
            <ul className="SideNavHomeList">
              {navDetails.map((items, index) => (
                <div key={index} className="SideNavLinkContainer">
                  <div className="OverFlowHidden">
                    <div className="SideNavLinkItemContainer">
                      <div className="SideNavLinkItemContainerWrapper">
                        <NavLink
                          to={
                            items.navHead === "Networking"
                              ? "/networking"
                              : items.navHead === "Trading"
                              ? "/trading"
                              : items.navHead === "Staking & Mining"
                              ? "/staking"
                              : items.navHead === "Smart Wallet"
                              ? "/wallet"
                              : items.navHead === "IDO List"
                              ? "ido"
                              : ""
                          }
                          onClick={() => toggle(items.navId)}
                        >
                          <div className="SideNavLinkItemContainerInner">
                            <div className="SideNavLinkItemContainerInnerWrapper">
                              <span
                                className={
                                  items.navHead === "Networking"
                                    ? "SideNavLinkIcon PortfolioIcon"
                                    : items.navHead === "Trading"
                                    ? "SideNavLinkIcon TradingIcon"
                                    : items.navHead === "Staking & Mining"
                                    ? "SideNavLinkIcon StakingIcon"
                                    : items.navHead === "Smart Wallet"
                                    ? "SideNavLinkIcon WalletIcon"
                                    : "SideNavLinkIcon LaunchIcon"
                                }
                              >
                                {" "}
                              </span>
                            </div>
                          </div>
                          <span className="SideNavLinkText">
                            {" "}
                            {items.navHead}{" "}
                          </span>
                        </NavLink>
                      </div>
                      {open === items.navId && (
                        <div className="SideNavLinkSubItemsContainer">
                          <div className="SideNavLinkSubItemsWrapper">
                            <div>
                              <span className="SideNavLinkSubItem">
                                {" "}
                                {items.subNavItems.map((navItem, index) => (
                                  <NavLink
                                    key={index}
                                    to={subNavFunction(items.navLink, navItem)}
                                  >
                                    <div className="SideNavLinkSubItemInner">
                                      <span className="SideNavLinkSubItem">
                                        {" "}
                                        {navItem}
                                      </span>
                                    </div>
                                  </NavLink>
                                ))}
                              </span>
                            </div>
                          </div>
                        </div>
                      )}
                    </div>
                  </div>
                </div>
              ))}
            </ul>
          </div>
        </div>
      </div>
    </div>
  );
};

https://codesandbox.io/s/tayyab-navigation-zlpyh?file=/src/SideNav.js

【讨论】:

    猜你喜欢
    • 2015-08-16
    • 1970-01-01
    • 1970-01-01
    • 2014-07-31
    • 2017-07-16
    • 2018-12-26
    • 2023-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多