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

时间:2019-06-27 12:25:02

标签: javascript css reactjs

我正在尝试在边栏中创建可折叠列表。单击时,我正在更改“ 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>
  );
};

4 个答案:

答案 0 :(得分:4)

尝试创建具有折叠元素状态的对象,如下所示:

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;

结帐the sandbox

让我知道是否有帮助。

答案 1 :(得分:1)

编辑:

我做了一个新的codesandbox,直到我添加了一些过渡效果。现在打开和关闭都很顺利。


选中this 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>
  );
};

答案 2 :(得分:0)

您可以在不使用状态的情况下解决此问题。尝试更改为此

<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;
}

答案 3 :(得分:0)

这当然并不比@axeljunes好,但它也可以工作,因此我维护了一个单独的已切换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;