मेनू एक सही इंडेक्स दिवा नहीं खोल रहा है


11

गाय का I एक समस्या का सामना कर रहा है। मेरे पास 2-आयामी डेटा है। डेटा में एक नेस्टेड संरचना होती है जिसमें लिंक होते हैं।

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लेकिन मेरी अनुक्रमण सही ढंग से काम नहीं कर रहा है और एक सही पैनल नहीं खोल रहा है। आप क्रोम इंस्पेक्टर पैनल पर मेरे समाधान का निरीक्षण कर सकते हैं। मैं इसकी सराहना करता हूं यदि आप मुझे बताते हैं कि मैं क्या गलत कर रहा हूं?

मेरा कोड सैंडबॉक्स लिंक

कोड:

// 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

यह पहली बार में बहुत सारे बदलावों की तरह लग सकता है, इसलिए मैं थोड़ा विस्तार करूँगा:

  • मैंने मेनू हेडर और मेन्यू आइटम सूची को अपने स्वयं के घटकों में आसानी से पुन: उपयोग करने की अनुमति दी
  • मैंने आपके डेटा संरचना को फिर से लिखा है, ताकि आपको दो बार या तीन बार भी मेनू आइटम को परिभाषित करने की आवश्यकता न हो। यह संरचना सपाट है, जो आपको आसानी से डेटाबेस में संग्रहीत करने की अनुमति देती है जो आप चाहते हैं।

मैं उसकी जांच करूंगा।
जॉन चक्स

पहले सही माता index- पिता के साथ सरणी को समतल करना और फिर इस मेनू को उत्पन्न करना एक अच्छा विचार है । वैसे, डेटा बाहरी एपीआई से आ रहा है। लेकिन समस्या को हल करने के लिए अपने दृष्टिकोण का उपयोग करना वास्तव में सहायक है।
जॉन चक्स

सराहना करें कि यह सहायक है। यदि यह आपकी समस्या को हल करता है, तो आप इसे स्वीकार किए जाते हैं। अन्यथा, मुझे बताएं कि क्या आपको कुछ और जानकारी चाहिए।
राउटरलैंड

जावास्क्रिप्ट में पदानुक्रमित डेटा संरचना को बचाने के लिए सबसे अच्छा तरीका क्या है? क्या हमें बच्चों को एक आयामी सरणी के अंदर घोंसला बनाना है या हमें उन वस्तुओं के साथ सरणी को समतल करना होगा जिनके पास मूल आईडी का संदर्भ है? आपने क्या सुझाव दिया?
जॉन चक्स

यह उपयोग के मामले पर निर्भर करता है। यदि आप सुनिश्चित हैं कि आप केवल एक बार डेटा का उपयोग करेंगे और यदि प्रदर्शन महत्वपूर्ण है, तो इसके पदानुक्रमित रूप में संग्रहीत करने के लिए कुछ कहना है। हालांकि, यदि आप एक ही डेटा को अलग-अलग तरीकों से उपयोग कर सकते हैं, तो मुझे लगता है कि इसे जितना संभव हो उतना फ्लैट स्टोर करना अक्सर आसान होता है।
राउटरलैंड

1

मुझे लगता है कि आपको बस जरूरत है

handlePanelBtn(item.title, childItemIndex, prevId)

के बजाय

handlePanelBtn(item.title, index, prevId)

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


आपके कोडैंडबॉक्स में जब मैं productsसूची-आइटम nextबटन पर क्लिक करता हूं । यह productsसूची मद के बच्चों को नहीं खोल रहा है ।
जॉन चक्स

0

मैंने पैनल को दिखाने के आपके तर्क को आसान बनाने के लिए संदर्भ एपीआई के साथ ऐसा किया है।

पैनलकोनटेक्स्ट नामक संदर्भ बनाएं जिसमें पैनल सरणी है जिसका उपयोग वर्तमान पैनल दिखाने और मेनू में वापस जाने के लिए किया जा सकता है।

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

मैंने तुम्हारा सीएसएस तोड़ दिया है।

और गहरी नेस्टेड बच्चों के साथ केवल एक ही वस्तु का उपयोग किया।

यहाँ काम कर रहा है कोडैंडबॉक्स: https://codesandbox.io/s/panel-menu-c871j


जवाब के लिए धन्यवाद वास्तव में सराहना करते हैं।
जॉन चक्स

आपका स्वागत है!
अमित चौहान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.