상세 컨텐츠

본문 제목

괘니 만들어보는 사이드 메뉴

자바스크립트

by e7e 2024. 6. 3. 21:52

본문

오른쪽 슬라이딩 메뉴를  만들어본 김에 사이드 메뉴도 한번 맹글어보장.

자꾸 다른 사람이 만든 걸 가져다만 쓰려하면 정작 필요한 기본 로직 작성 능력이

늘지를 않는당.~~ 이건 큰 문제당.

 

역시 항상 그렇진 않지만, 한번 맹글어보면 생각처럼 어려울 건 없당.

그리고 화면으로 로직연습을 하는 건 정말 재밌게 로직 능력을 키워준당.

 

아래 소스를 복사/붙여넣기로 실행해 보공,(css 빼면 양도 별로 안됨!)

차분히 뽀인또를 이해한 다음에, 입맛에 맞게 수정/추가 해 보길 권장! 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>사이드바 메뉴 참공</title>
    <style>
      #menuWrapper {
        width: 200px;
        text-align: center;
        border: 5px solid pink;
      }
      .hide {
        display: none;
      }

      .show {
        display: block;
        color: white;
        font-weight: bolder;
      }

      .mmain {
        cursor: pointer;
      }

      #menuTemp {
        display: none;
      }
      .menu {
        margin-bottom: 10px;
        text-decoration: underline;
      }
    </style>
  </head>
  <body>
    <button onclick="fAddMenus()">확인용 메뉴추가 버튼</button>
    <hr />
    <div id="menuWrapper">
      <!-- 복사해서 쓸 html 템플릿, 요따구로 쓰면 꽤나 편함-->
      <div id="menuTemp" class="menu">
        <div class="mmain" onclick="fsubClick(this)">메뉴이름</div>
        <div class="msub hide">
          <ul>
            <li>서브메뉴1</li>
            <li>서브메뉴2</li>
            <li>서브메뉴3</li>
            <li>서브메뉴4</li>
          </ul>
        </div>
      </div>
    </div>
    <script>
      // 기본 틀
      const menuWrapper = document.querySelector("#menuWrapper");
      const menuTemp = document.querySelector("#menuTemp");
      let curMenuNum = 0;

      function fRanColor() {
        return `rgb(
          ${Math.floor(Math.random() * 256)},
          ${Math.floor(Math.random() * 256)},
          ${Math.floor(Math.random() * 256)}
        )`;
      }
      // 처음 클릭하거나, 같은 메뉴 클릭
      function fSelfToggle(eDiv) {
        curMenuNum = eDiv.parentElement.id.split("-")[1];
        let subDiv = eDiv.nextElementSibling; // eDiv.parentElement.children[1]
        let curState = subDiv.classList.contains("hide");
        if (curState) {
          subDiv.classList.remove("hide");
          subDiv.classList.add("show");
          subDiv.style.backgroundColor = fRanColor();
          return;
        }
        subDiv.classList.remove("show");
        subDiv.classList.add("hide");
      }

      // 다른 메뉴 클릭
      function fDiffClick(eDiv) {
        let subDiv = menuWrapper.querySelector(`#menu-${curMenuNum}`).children[1];
        subDiv.classList.remove("show");
        subDiv.classList.add("hide");

        subDiv = eDiv.nextElementSibling; // eDiv.parentElement.children[1]
        curMenuNum = eDiv.parentElement.id.split("-")[1];
        subDiv.classList.remove("hide");
        subDiv.classList.add("show");
        subDiv.style.backgroundColor = fRanColor();
      }

      function fsubClick(eDiv) {
        if (!curMenuNum || curMenuNum == eDiv.parentElement.id.split("-")[1]) {
          fSelfToggle(eDiv);
        } else {
          fDiffClick(eDiv);
        }
      }

      let i = 1; // 그냥 id 구분용 전역 변수
      // 메뉴 추가 함수
      function fAddMenus() {
        const menuClone = menuTemp.cloneNode(true);
        menuClone.setAttribute("id", `menu-${i}`);
        menuClone.querySelector(".mmain").textContent = `메뉴${i}`;
        const lis = menuClone.querySelectorAll("li");
        lis.forEach((li, idx) => {
          console.log(li);
          li.textContent = `서브${i}-${idx}`;
        });
        i++;
        menuWrapper.append(menuClone);
        menuClone.style.display = "block";
      }
    </script>
  </body>
</html>

 

나의 경우 결과는 아래와 같았당.! 

 

위 소스가 이해 되었다면, 메뉴 구조도를  매개변수로 받아서 한번에 메뉴를 넣는

방식도 구현해 보장. (역시 막상 해보면 머얌 쉽넹 할 정도로 쉽당!)

심플하게 아래와 같은 메뉴 구조도(json형식)를 매개변수로 받는 다고 가정! 

 const menus = [
        {
          main: "블랙핑크",
          subs: ["로제", "제니", "리사","지수"],
          fgColor:"yellow",
          bgColor:"black"

        },
        {
          main: "IVE",
          subs: ["안유진", "가을", "레이", "장원영","리즈","이서"],
          fgColor:"white",
          bgColor:"darkgreen"
        },
        {
          main: "에스파",
          subs: ["카리나", "지젤", "윈터", "닝닝"],
          fgColor:"yellow",
          bgColor:"purple"
        },
        {
          main: "레드벨벳",
          subs: ["아이린", "슬기", "웬디", "조이","예리"],
          fgColor:"white",
          bgColor:"red"
        },
      ];

 

대략 아래와 흐름이 비스무리한 소스가 만들어 질 것이당.

(오늘따라 생각이 튀어나오지 않는다면, 그냥 복사/붙여넣기로 흐름만 따라가보자)

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <title>사이드바 메뉴 참공</title>
    <style>
      #menuWrapper {
        width: 200px;
        text-align: center;
        border: 5px solid pink;
        display: none;
      }
      .hide {
        display: none;
      }

      .show {
        display: block;
        color: white;
        font-weight: bolder;
      }

      .mmain {
        cursor: pointer;
      }

      #menuTemp {
        display: none;
      }
      .menu {
        margin-bottom: 10px;
        font-weight: bolder;
      }
      .tleft {
        text-align: left;
        cursor: pointer;
      }
      .line {
        margin-top: 5px;
        width:210px;
        height:5px;
        background-color: blueviolet;
      }
    </style>
  </head>
  <body>
    <button onclick="fMakeMenu()">한번에 메뉴구성 눌렁</button>
    <div class="line"></div>
    <div id="menuWrapper">
      <!-- 복사해서 쓸 html 템플릿, 요따구로 쓰면 꽤나 편함-->
      <div id="menuTemp" class="menu">
        <div class="mmain" onclick="fsubClick(this)">메뉴이름</div>
        <div class="msub hide">
          <ul>
            <li>서브메뉴1</li>
            <li>서브메뉴2</li>
            <li>서브메뉴3</li>
            <li>서브메뉴4</li>
          </ul>
        </div>
      </div>
    </div>
    <script>
      // 기본 틀
      const menuWrapper = document.querySelector("#menuWrapper");
      const menuTemp = document.querySelector("#menuTemp");
      let curMenuNum = 0;

      function fRanColor() {
        return `rgb(
          ${Math.floor(Math.random() * 256)},
          ${Math.floor(Math.random() * 256)},
          ${Math.floor(Math.random() * 256)}
        )`;
      }
      // 처음 클릭하거나, 같은 메뉴 클릭
      function fSelfToggle(eDiv) {
        curMenuNum = eDiv.parentElement.id.split("-")[1];
        let subDiv = eDiv.nextElementSibling; // eDiv.parentElement.children[1]
        let curState = subDiv.classList.contains("hide");
        if (curState) {
          subDiv.classList.remove("hide");
          subDiv.classList.add("show");
          subDiv.style.backgroundColor = fRanColor();
          return;
        }
        subDiv.classList.remove("show");
        subDiv.classList.add("hide");
      }

      // 다른 메뉴 클릭
      function fDiffClick(eDiv) {
        let subDiv = menuWrapper.querySelector(`#menu-${curMenuNum}`)
          .children[1];
        subDiv.classList.remove("show");
        subDiv.classList.add("hide");

        subDiv = eDiv.nextElementSibling; // eDiv.parentElement.children[1]
        curMenuNum = eDiv.parentElement.id.split("-")[1];
        subDiv.classList.remove("hide");
        subDiv.classList.add("show");
        subDiv.style.backgroundColor = fRanColor();
      }

      function fsubClick(eDiv) {
        if (!curMenuNum || curMenuNum == eDiv.parentElement.id.split("-")[1]) {
          fSelfToggle(eDiv);
        } else {
          fDiffClick(eDiv);
        }
      }

      const fSub = (msub) => {
        alert(`${msub.innerHTML}을 누르셨어용!`);
      };

      let i = 1;
      const fAddMenus = (menus) => {
        menus.forEach((menu) => {
          let tempMenu = menuTemp.cloneNode(true);
          tempMenu.id = `menu-${i}`;
          tempMenu.children[0].textContent = menu.main;
          let submenuStr = "<ul>";
          menu.subs.forEach((subMenu) => {
            submenuStr += `<li class="tleft" onclick="fSub(this)"
                              style="color:${menu.fgColor};background-color:${menu.bgColor}"
                           >${subMenu}</li>`;
          });
          submenuStr += "</ul>";

          console.log("체킁킁:", tempMenu.children[1]);
          tempMenu.children[1].innerHTML = submenuStr;
          menuWrapper.appendChild(tempMenu);
          tempMenu.style.display = "block";
          i++;
        });
        console.log("체킁:", menus);
      };

      // 한번에 메뉴 정의!
      const menus = [
        {
          main: "블랙핑크",
          subs: ["로제", "제니", "리사","지수"],
          fgColor:"yellow",
          bgColor:"black"

        },
        {
          main: "IVE",
          subs: ["안유진", "가을", "레이", "장원영","리즈","이서"],
          fgColor:"white",
          bgColor:"darkgreen"
        },
        {
          main: "에스파",
          subs: ["카리나", "지젤", "윈터", "닝닝"],
          fgColor:"yellow",
          bgColor:"purple"
        },
        {
          main: "레드벨벳",
          subs: ["아이린", "슬기", "웬디", "조이","예리"],
          fgColor:"white",
          bgColor:"red"
        },
      ];

      function fMakeMenu(){
        fAddMenus(menus);
        menuWrapper.style.display="block";
      }
    </script>
  </body>
</html>

 

난 아래와 같은  결과를 얻었당. (더 잼나고 이쁘겡 추가 수정은 본인 몫이당)

있어보이지 않아서 쪼금은 실망이지만, CSS를 더 하고 싶진 않당.~~

 


 

진실의 양면성 진실은 

맘 가운데 큰 길을 만든다.

 

진실이 진실일 수도

진실이 진실이 아닐수도

진실이었다가, 진실이 아닐수도

그 역도 진실일 수도 아닐수도

결국 진실이 아닌게 진실일수도.......

 

이때 그 누군가 나타나 이건 진실이고,

저건 거짓이야라고 정해준당.

그냥 넘 고맙당.

 

대신 그 누군가는 Off The Record여야 한당.

그 누군가는 끝내 진실이 된당.

 

https://www.youtube.com/watch?v=Kn0NJzKAPLE

 

관련글 더보기