如何在侧边栏中列出可折叠列表



我正在尝试在侧边栏中列出可折叠列表。在单击时,我要更改" iSopen"状态,并取决于我要显示或隐藏子链接的状态。问题在于所有子链接同时打开。

检查沙箱:https://codesandbox.io/s/infallible-moore-h16g6

const Sidebar = ({ title, children, data, opened, ...attrs }) => {
  const [isOpen, setTriger] = useState(false);
  const handleClick = idx => {
    setTriger(!isOpen)
  };
  return (
    <SidebarUI>
      {data.map((item, idx) => {
        return typeof item.data === "string" ?
        <div key={idx} >{item.name}</div>:
          <Fragment key={idx}>
            <div onClick={() => handleClick(idx)}>{item.name}</div>
            { item.data.map((subs, ids) => {
              return <Test isOpen={isOpen} key={ids}>++++{subs.name}</Test>;
            })}
          </Fragment>
      })}
    </SidebarUI>
  );
};

尝试以折叠元素的状态创建一个对象,例如:

const Sidebar = ({ title, children, data, opened, ...attrs }) => {
  const [collapseElements, setCollapse] = useState({});
  const handleClick = idx => {
    const currentElements = Object.assign({}, collapseElements);
    setCollapse({ ...currentElements, [idx]: !collapseElements[idx] });
  };
  return (
    <SidebarUI>
      {data.map((item, idx) => {
        return typeof item.data === "string" ? (
          <div key={idx}>{item.name}</div>
        ) : (
          <Fragment key={idx}>
            <div onClick={() => handleClick(idx)}>{item.name}</div>
            {item.data.map((subs, ids) => {
              return (
                <Test isOpen={collapseElements[idx]} key={ids}>
                  ++++{subs.name}
                </Test>
              );
            })}
          </Fragment>
        );
      })}
    </SidebarUI>
  );
};
export default Sidebar;

检查沙箱。

让我知道它是否有帮助。

编辑:

我做了一个新的代码和盒子,我添加了一些过渡。现在打开和关闭平稳。


检查此codesandbox

现在打开并关闭。

您要做的是保留您单击的index,并且仅在相同的index时显示孩子。

我还添加了一种关闭和打开的方法。

这里是通过您的问题中的代码来执行的。

const Sidebar = ({ title, children, data, opened, ...attrs }) => {
  const [openedIndex , setTriger] = useState(false);
  const handleClick = idx => {
    // this ternary makes it possible to open and close 
    setTriger(idx === openedIndex ? -1 : idx)
  };
  return (
    <SidebarUI>
      {data.map((item, idx) => {
        return typeof item.data === "string" ?
        <div key={idx} >{item.name}</div>:
          <Fragment key={idx}>
            <div onClick={() => handleClick(idx)}>{item.name}</div>
            {// here you check if the idx is the same as the opened one}
            {// before showing the data of the item}
            {idx === openedIndex && item.data.map((subs, ids) => {
              return <Test isOpen={true} key={ids}>++++{subs.name}</Test>;
            })}
          </Fragment>
      })}
    </SidebarUI>
  );
};

您无需使用状态即可解决此问题。尝试更改为此

<Fragment key={idx}>
  <div class="sidebar-item" onClick={e => openSidebar(e)}>
    {item.name}
  </div>
  {item.data.map((subs, ids) => {
   return (
      <div className="sidebar-subitem" key={ids}>
        ++++{subs.name}
      </div>
    );
  })}
</Fragment>

单击"切换类"

 function openSidebar(e) {
    e.preventDefault();
    e.target.classList.toggle("open");
  }

添加CSS

.sidebar-subitem {
  display: none;
}
.sidebar-item.open + .sidebar-subitem {
  display: block;
}

这当然不比@axeljunes好,但也可以工作,因此我保留了一个单独的togggled ID列表,并且基于它可以切换。这也是我第一次使用钩子,所以裸露我(随意纠正我(

const Sidebar = ({ title, children, data, opened, ...attrs }) => {
  //const [isOpen, setTriger] = useState(false);
  const [list, setList] = useState([]);
  const handleClick = idx => {
    //setTriger(!isOpen);
    if(!list.includes(idx))
      setList([...list,idx]);
    else{      
      const newList = list.filter(e => e!==idx);
      setList(newList);
    }
  };
  return (
    <SidebarUI>
      {data.map((item, idx) => {
        return typeof item.data === "string" ? (
          <div key={idx}>{item.name}MAIN</div>
        ) : (
          <Fragment key={idx}>
            <div onClick={() => handleClick(idx)}>{item.name}IN</div>
            {item.data.map((subs, ids) => {
              return (
                <Test isOpen={list.includes(idx)} key={ids}>
                  ++++{subs.name}SIDE
                </Test>
              );
            })}
          </Fragment>
        );
      })}
    </SidebarUI>
  );
};
export default Sidebar;

最新更新