코딩

화면 너비에 따라 변하고 클릭 시 열리고 닫히는 메뉴 만들기

KUROMI98 2025. 7. 26. 13:19


html

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <title>Menu</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="grid-container"></div>
    <script src="script.js"></script>
  </body>
</html>

js

const mqMobile = window.matchMedia("(max-width: 600px)");
const mqDesktop = window.matchMedia("(min-width: 601px)");

const gridContainer = document.querySelector(".grid-container");

function clearGrid() {
  gridContainer.innerHTML = "";
}

function createSubmenuElements(submenus) {
  return submenus.map((sub) => {
    const submenu = document.createElement("div");
    submenu.className = "submenu";
    submenu.textContent = sub;
    return submenu;
  });
}

function renderMenus(menuData) {
  clearGrid();

  menuData.forEach((menus) => {
    const menuContainer = document.createElement("div");
    menuContainer.className = "menu-container";

    menus.mainmenus.forEach((menu) => {
      const menuDiv = document.createElement("div");

      const mainmenu = document.createElement("div");
      mainmenu.className = "mainmenu";
      mainmenu.textContent = menu.title;

      if (mqDesktop.matches) {
        menuDiv.appendChild(mainmenu);

        const submenuElements = createSubmenuElements(menu.submenus);
        submenuElements.forEach((el) => menuDiv.appendChild(el));
      } else {
        const submenuWrapper = document.createElement("div");
        submenuWrapper.style.display = "none";

        const submenuElements = createSubmenuElements(menu.submenus);
        submenuElements.forEach((el) => submenuWrapper.appendChild(el));

        mainmenu.addEventListener("click", () => {
          const isVisible = submenuWrapper.style.display === "block";
          submenuWrapper.style.display = isVisible ? "none" : "block";
        });

        menuDiv.appendChild(mainmenu);
        menuDiv.appendChild(submenuWrapper);
      }

      menuContainer.appendChild(menuDiv);
    });

    gridContainer.appendChild(menuContainer);
  });
}

fetch("menudata.json")
  .then((res) => res.json())
  .then((menuData) => {
    renderMenus(menuData);
    window.addEventListener("resize", () => {
      renderMenus(menuData);
    });
  })
  .catch((error) => {
    console.error("메뉴 데이터를 불러오는 데 실패했습니다:", error);
  });

css

body {
  padding: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.grid-container {
  max-width: 1600px;
  width: 100%;
  gap: 16px;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 32px;
}
.menu-container {
  display: flex;
  flex-direction: column;
  gap: 48px;
}
.mainmenu {
  font-size: 14px;
}
.submenu {
  font-size: 12px;
  color: gray;
}

@media (max-width: 600px) {
  .grid-container {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    flex-wrap: nowrap;
    gap: 0px;
  }
  .menu-container {
    gap: 0px;
  }
}


json

[
  {
    "mainmenus": [
      {
        "title": "메뉴 1",
        "submenus": [
          "사이드메뉴 1a",
          "사이드메뉴 1b",
          "사이드메뉴 1c",
          "사이드메뉴 1d",
          "사이드메뉴 1e",
          "사이드메뉴 1f",
          "사이드메뉴 1g",
          "사이드메뉴 1h",
          "사이드메뉴 1i",
          "사이드메뉴 1j",
          "사이드메뉴 1k",
          "사이드메뉴 1l",
          "사이드메뉴 1m",
          "사이드메뉴 1n"
        ]
      }
    ]
  },
  {
    "mainmenus": [
      {
        "title": "메뉴 2-1",
        "submenus": ["사이드메뉴 2-1a", "사이드메뉴 2-1b", "사이드메뉴 2-1c"]
      },
      {
        "title": "메뉴 2-2",
        "submenus": ["사이드메뉴 2-2a", "사이드메뉴 2-2b"]
      },
      {
        "title": "메뉴 2-3",
        "submenus": ["사이드메뉴 2-3a", "사이드메뉴 2-3b"]
      }
    ]
  },
  {
    "mainmenus": [
      {
        "title": "메뉴 3",
        "submenus": [
          "사이드메뉴 3a",
          "사이드메뉴 3b",
          "사이드메뉴 3c",
          "사이드메뉴 3d",
          "사이드메뉴 3e",
          "사이드메뉴 3f",
          "사이드메뉴 3g"
        ]
      }
    ]
  },
  {
    "mainmenus": [
      {
        "title": "메뉴 4-1",
        "submenus": [
          "사이드메뉴 4-1a",
          "사이드메뉴 4-1b",
          "사이드메뉴 4-1c",
          "사이드메뉴 4-1d",
          "사이드메뉴 4-1e"
        ]
      },
      {
        "title": "메뉴 4-2",
        "submenus": ["사이드메뉴 4-2a", "사이드메뉴 4-2b"]
      },
      {
        "title": "메뉴 4-3",
        "submenus": ["사이드메뉴 4-3a"]
      }
    ]
  },
  {
    "mainmenus": [
      {
        "title": "메뉴 5",
        "submenus": [
          "사이드메뉴 5a",
          "사이드메뉴 5b",
          "사이드메뉴 5c",
          "사이드메뉴 5d",
          "사이드메뉴 5e",
          "사이드메뉴 5f",
          "사이드메뉴 5g",
          "사이드메뉴 5h",
          "사이드메뉴 5i",
          "사이드메뉴 5j",
          "사이드메뉴 5k",
          "사이드메뉴 5l",
          "사이드메뉴 5m",
          "사이드메뉴 5n"
        ]
      }
    ]
  }
]