เมนูไม่เปิด div ดัชนีที่ถูกต้อง


11

Guy ฉันกำลังเผชิญปัญหาอยู่ ฉันมีข้อมูลสองมิติ ข้อมูลมีโครงสร้างแบบซ้อนที่มีลิงค์อยู่

const data = [
  // First Div Panel 
  [
    {
      id: 1,
      url: "/services",
      title: "Services"
    },
    {
      id: 2,
      title: "Products",
      children: [
        {
          id: 3,
          url: "/themes-templates",
          title: "Themes & Templates"
        },
        {
          id: 4,
          url: "/open-source",
          title: "Open Source"
        },
        {
          id: 5,
          url: "/solutions",
          title: "Solutions"
        }
      ]
    },
    {
      id: 6,
      url: "/work",
      title: "Work",
      children: [
        {
          id: 7,
          url: "/methodology",
          title: "Methodology",
          children: [
            {
              id: 8,
              url: "/agile",
              title: "Agile",
              children: [
                {
                  id: 9,
                  url: "/scrum",
                  title: "Scrum"
                }
              ]
            }
          ]
        }
      ]
    },
    {
      id: 10,
      url: "/contact-us",
      title: "Contact Us"
    }
  ],
  // Second Div Panel which contains children of second list item
  [
    {
      id: 3,
      url: "/themes-templates",
      title: "Themes & Templates"
    },
    {
      id: 4,
      url: "/open-source",
      title: "Open Source"
    },
    {
      id: 5,
      url: "/solutions",
      title: "Solutions"
    }
  ],
  // Third Div Panel which contains children of third list item
  [
    {
      id: 7,
      url: "/methodology",
      title: "Methodology",
      children: [
        {
          id: 8,
          url: "/agile",
          title: "Agile",
          children: [
            {
              id: 9,
              url: "/scrum",
              title: "Scrum"
            }
          ]
        }
      ]
    }
  ],
  // Fourth Div Panel contains the children of the 3rd sub list item
  [
    {
      id: 8,
      url: "/agile",
      title: "Agile",
      children: [
        {
          id: 9,
          url: "/scrum",
          title: "Scrum"
        }
      ]
    }
  ],
  // Fourth Div Panel contains the children of the 3rd sub sub list item
  [
    {
      id: 9,
      url: "/scrum",
      title: "Scrum"
    }
  ]
];

งานของฉันคือใช้ข้อมูล 2 มิตินั้นและสร้างเมนูมือถือ reactที่มีโครงสร้างคล้ายแผงพุช

อย่างไรก็ตามฉันพยายามที่จะสร้างเช่นนี้ divสิ่งที่ฉันได้คือผมได้รับการรักษาทุกย่อยอาร์เรย์เป็นแผงแยกต่างหาก ก่อนรายการย่อยจะได้รับการพิจารณาในแผงรากซึ่งเป็นค่าเริ่มต้นที่มองเห็นได้ หากรายการมีchildrenคุณสมบัติแสดงว่ามีการnextสร้างปุ่มแบบไดนามิกในรายการนั้น เมื่อเราคลิกที่ปุ่มนี้มันจะเพิ่มis-visibleคลาสบนพาเนล แต่คำถามคือวิธีการที่จะติดตามแผงมีความเกี่ยวข้องกับปุ่มที่คลิก ? ฉันพยายามที่จะใช้รัฐที่มีactiveIdและprevIdแต่การจัดทำดัชนีของฉันไม่ถูกต้องในการทำงานและไม่ได้เปิดแผงที่ถูกต้อง คุณสามารถตรวจสอบวิธีการแก้ปัญหาของฉันบนแผงตรวจสอบโครเมี่ยม ฉันซาบซึ้งถ้าคุณบอกฉันว่าฉันทำอะไรผิด

รหัส sandbox ของฉันลิงค์

รหัส:

// Get a hook function
const {useState} = React;

//#region Data
const data = [
  // First Div Panel
  [
    {
      id: 1,
      url: "/services",
      title: "Services"
    },
    {
      id: 2,
      title: "Products",
      children: [
        {
          id: 3,
          url: "/themes-templates",
          title: "Themes & Templates"
        },
        {
          id: 4,
          url: "/open-source",
          title: "Open Source"
        },
        {
          id: 5,
          url: "/solutions",
          title: "Solutions"
        }
      ]
    },
    {
      id: 6,
      url: "/work",
      title: "Work",
      children: [
        {
          id: 7,
          url: "/methodology",
          title: "Methodology",
          children: [
            {
              id: 8,
              url: "/agile",
              title: "Agile",
              children: [
                {
                  id: 9,
                  url: "/scrum",
                  title: "Scrum"
                }
              ]
            }
          ]
        }
      ]
    },
    {
      id: 10,
      url: "/contact-us",
      title: "Contact Us"
    }
  ],
  // Second Div Panel
  [
    {
      id: 3,
      url: "/themes-templates",
      title: "Themes & Templates"
    },
    {
      id: 4,
      url: "/open-source",
      title: "Open Source"
    },
    {
      id: 5,
      url: "/solutions",
      title: "Solutions"
    }
  ],
  // Third Div Panel
  [
    {
      id: 7,
      url: "/methodology",
      title: "Methodology",
      children: [
        {
          id: 8,
          url: "/agile",
          title: "Agile",
          children: [
            {
              id: 9,
              url: "/scrum",
              title: "Scrum"
            }
          ]
        }
      ]
    }
  ],
  // Fourth Div Panel
  [
    {
      id: 8,
      url: "/agile",
      title: "Agile",
      children: [
        {
          id: 9,
          url: "/scrum",
          title: "Scrum"
        }
      ]
    }
  ],
  // Fifth Div Panel
  [
    {
      id: 9,
      url: "/scrum",
      title: "Scrum"
    }
  ]
];
//#endregion Data

//#region Component


const PanelMenu = props => {
  const { title } = props;

  const [items, setItems] = useState(data);

  // Title Header of the Panel
  const [headerTitle, setHeaderTitle] = useState(title ? title : "");
  // Previous Title Header of the Panel
  const [prevHeaderTitle, setPrevHeaderTitle] = useState(title ? title : "");
  // ActiveIndex => 0 means by default master-panel is active
  const [activeId, setActiveId] = useState(0);
  // PreviousIndex
  const [prevId, setPrevId] = useState(0);

  const handlePanelBtn = (newTitle, index, prevIndex) => {
    // Title Checking
    const titleProp = title ? title : "";
    const prevTitle = index === 0 ? titleProp : headerTitle;
    // SetStates
    setPrevHeaderTitle(prevTitle);
    setHeaderTitle(newTitle);
    setActiveId(index);
    setPrevId(prevIndex);
  };

  const panelRenderer = () => {
    const panelsJSX = [];
    for (let i = 0; i < items.length; i++) {
      let childItemIndex = i;
      const panels = (
        <div
          key={i}
          id={i === 0 ? "p__master" : `p__student-${i}`}
          className={
            childItemIndex === activeId
              ? "p__panel is-visible"
              : "p__panel is-hide"
          }
        >
          <ul>
            {items[i].map((item, index) => {
              // It means it have children
              if (item.children && item.children.length > 0) {
                childItemIndex++;
                return (
                  <li key={item.id} className="p-next">
                    {item.url ? (
                      <a href={item.url} className="p-link">
                        {item.title}
                      </a>
                    ) : (
                      <div className="p-link">{item.title}</div>
                    )}
                    <button
                      type="button"
                      className="p-next__btn"
                      data-id={`#p__student-${childItemIndex}`}
                      onClick={() => handlePanelBtn(item.title, index, prevId)}
                    >
                      <span>&gt;</span>
                    </button>
                  </li>
                );
              } else {
                return (
                  <li key={item.id}>
                    <a href={item.url} className="p-link">
                      {item.title}
                    </a>
                  </li>
                );
              }
            })}
          </ul>
        </div>
      );

      panelsJSX.push(panels);
    }
    return panelsJSX;
  };

  const renderer = () => {
    if (items && items.length > 0) {
      return (
        <div className="p">
          <div className="p__wrap">
            {/* Panel Actions => Header */}
            <div className="p__actions">
              {/* Previous Button */}

              {activeId !== 0 && (
                <button
                  type="button"
                  className="p-action__btn left"
                  onClick={() =>
                    handlePanelBtn(prevHeaderTitle, prevId, prevId)
                  }
                >
                  <span>&lt;</span>
                </button>
              )}

              {/* Title */}
              {headerTitle && (
                <div className="p-action__title">{headerTitle}</div>
              )}

              {/* Close Button */}
              <button type="button" className="p-action__btn right">
                <span>×</span>
              </button>
            </div>
            {/* Panel children Wrapper */}
            <div className="p__children">{panelRenderer()}</div>
          </div>
        </div>
      );
    }
  };
  return <React.Fragment>{renderer()}</React.Fragment>;
};

//#endregion Component



// Render it
ReactDOM.render(
  <PanelMenu title="Menu" />,
  document.getElementById("root")
)
<style>

*,:before,:after {
    box-sizing: border-box;
}


.p__wrap {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 320px;
    background-color: #fff;
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
    z-index: 1;
    color: #333;
    overflow-x: hidden;
}

.p__actions {
    position: relative;
    padding: 14px;
    min-height: 54px;
    border-bottom: 1px solid #dcdcdc;
}

.p-action__title {
    text-align: center;
    color: #333;
    text-transform: uppercase;
    font-weight: 700;
}

.p-action__btn {
    position: absolute;
    width: 54px;
    height: 54px;
    top: 0;
    right: 0;
    font-size: 16px;
    color: #333;
    border: none;
    cursor: pointer;
}

.left {
    left: 0;
}

.right {
    right: 0;
}

.p__children {
    position: relative;
    background-color: #fff;
    overflow: hidden;
    height: calc(100% - 54px);
}

.p__panel {
    overflow-x: hidden;
    overflow-y: auto;
    position: absolute;
    transform: translateX(100%);
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 0;
    transition: transform 0.2s ease 0s;
}

.p__panel.is-visible {
    transform: translateX(0);
    z-index: 1;
}

.p__panel.is-hide {
    opacity: 0;
    visibility: hidden;
}

.p__panel > ul {
    margin: 0;
    padding: 0;
}
.p__panel > ul > li {
    list-style: none;
    border-bottom: 1px solid #dcdcdc;
}
.p__panel > ul > li > .p-link {
    color: #333;
    display: block;
    line-height: 22px;
    font-size: 14px;
    padding: 14px 24px;
    background-color: transparent;
    cursor: pointer;
}



.p__panel > ul > li > .p-link:hover {
   background-color: #dcdcdc;
}

.p-next {
    position: relative;
}

.p-next__btn {
    position: absolute;
    padding: 14px 16px;
    font-size: 16px;
    line-height: 22px;
    top: 0;
    right: 0;
    background-color: rgb(240,240,240);
    color: #333;
    border: none;
    border-left: 1px solid #dcdcdc;
    cursor: pointer;
}

</style>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

คำตอบ:


3

ฉันไปข้างหน้าและเปลี่ยนรหัสของคุณเป็นตัวอย่างการทำงานในแซนด์บ็อกซ์รหัสต่อไปนี้: https://codesandbox.io/s/panel-menu-hfrmx?fontsize=14&hidenavigation=1&theme=dark

ดูเหมือนว่าจะมีการเปลี่ยนแปลงมากมายในตอนแรกดังนั้นฉันจะอธิบายรายละเอียดเล็กน้อย:

  • ฉันแยกส่วนหัวเมนูและรายการเมนูเป็นส่วนประกอบของตนเองเพื่อให้นำมาใช้ใหม่ได้ง่ายขึ้น
  • ฉันเขียนโครงสร้างข้อมูลของคุณใหม่เพื่อที่คุณไม่จำเป็นต้องกำหนดรายการเมนูสองครั้งหรือสามครั้ง โครงสร้างนี้แบนซึ่งช่วยให้คุณสามารถเก็บไว้ในฐานข้อมูลที่คุณต้องการได้อย่างง่ายดาย

ฉันจะตรวจสอบว่า
John Chucks

เป็นความคิดที่ดีที่จะทำให้อาร์เรย์เป็นอันดับแรกโดยใช้พาเรนต์ที่ถูกต้องindexแล้วสร้างเมนูนี้ อย่างไรก็ตามข้อมูลมาจาก API ภายนอก แต่การใช้วิธีการของคุณนั้นมีประโยชน์จริง ๆ ในการแก้ปัญหา
John Chucks

ขอบคุณที่เป็นประโยชน์ หากสามารถแก้ไขปัญหาของคุณคุณสามารถทำเครื่องหมายว่ายอมรับได้ มิฉะนั้นแจ้งให้เราทราบหากคุณต้องการข้อมูลเพิ่มเติม
Wouter Raateland

วิธีที่ดีที่สุดในการบันทึกโครงสร้างข้อมูลแบบลำดับชั้นใน javascript คืออะไร? เราจำเป็นต้องมีลูกซ้อนกันภายในอาเรย์หนึ่งมิติหรือไม่หรือเราต้องทำให้อาเรย์นั้นเรียบด้วยวัตถุที่มีการอ้างอิงถึงไอดีพาเรนต์หรือไม่? คุณแนะนำอะไร
John Chucks

ขึ้นอยู่กับกรณีการใช้งาน หากคุณมั่นใจว่าคุณจะใช้ข้อมูลเพียงครั้งเดียวและหากประสิทธิภาพมีความสำคัญคุณจะต้องพูดถึงการจัดเก็บข้อมูลในรูปแบบลำดับชั้น อย่างไรก็ตามหากคุณอาจใช้ข้อมูลเดียวกันในรูปแบบที่แตกต่างกันฉันคิดว่ามันเป็นวิธีที่ง่ายที่สุดในการจัดเก็บข้อมูลให้เรียบที่สุด
Wouter Raateland

1

ฉันคิดว่าคุณแค่ต้องการ

handlePanelBtn(item.title, childItemIndex, prevId)

แทน

handlePanelBtn(item.title, index, prevId)

https://codesandbox.io/s/panel-menu-2uwxo


ใน codesandbox ของคุณเมื่อฉันคลิกproductsรายการรายการnextปุ่ม มันไม่ได้เปิดลูกของproductsรายการ
John Chucks

0

ฉันทำสิ่งนี้ด้วยบริบท api เพื่อลดความซับซ้อนของตรรกะของคุณในการแสดงแผง

สร้างบริบทที่เรียกว่า PanelContext ซึ่งมีแผงอาร์เรย์ซึ่งสามารถใช้เพื่อแสดงแผงปัจจุบันและกลับไปที่เมนู

import React from "react";

export const PanelContext = React.createContext();
export function PanelProvider({ children }) {
  const [currentPanel, setCurrentPanel] = React.useState([0]);
  const addItemToPanel = item => setCurrentPanel(prev => [item, ...prev]);
  const goBack = () => setCurrentPanel(prev => prev.slice(1));
  return (
    <PanelContext.Provider
      value={{
        currentPanel: currentPanel[0],
        setCurrentPanel: addItemToPanel,
        goBack
      }}
    >
      {children}
    </PanelContext.Provider>
  );
}

และสร้างส่วนประกอบพาเนลซึ่งจะสร้างแผงทั้งหมดและแผงแสดงซ้ำซึ่งทำงานอยู่ตามค่าบริบท

const Panel = ({ items, id, title }) => {
  const { currentPanel, setCurrentPanel, goBack } = React.useContext(
    PanelContext
  );
  const panels = [];
  return (
    <>
      <div
        className={id === currentPanel ? "p__wrap visible" : " p__wrap hidden"}
      >
        <h2>
          {title && <button onClick={goBack}>{"<"}</button>} {title || "Menu"}{" "}
        </h2>
        <div className="p__panel">
          <ul>
            {items.map(item => {
              if (item.children)
                panels.push(
                  <Panel
                    title={item.title}
                    id={item.id}
                    items={item.children}
                  />
                );
              return (
                <React.Fragment key={item.id}>
                  <li>
                    {item.title}
                    {item.children && (
                      <button
                        onClick={() => {
                          setCurrentPanel(item.id);
                        }}
                      >
                        {">"}
                      </button>
                    )}
                  </li>
                </React.Fragment>
              );
            })}
          </ul>
        </div>
      </div>
      {panels}
    </>
  );
};
export const PanelMenu = props => {
  return (
    <PanelProvider>
      <Panel items={data} id={0} />
    </PanelProvider>
  );
};

ฉันทำลาย css ของคุณ

และใช้เพียงวัตถุเดียวกับเด็กที่ซ้อนกันอย่างล้ำลึก

นี่คือรหัสงานที่ใช้งานได้: https://codesandbox.io/s/panel-menu-c871j


ขอบคุณสำหรับคำตอบจริงๆขอบคุณที่
John Chucks

ยินดีต้อนรับคุณ!
Amit Chauhan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.