Tree View UI (실습)

Jelkov Ahn·2021년 10월 7일
0

JS/NODE(재귀함수)

목록 보기
3/3
post-thumbnail


const menu = [
  {
    type: 'group',
    name: '음료',
    children: [
      {
        type: 'group',
        name: '콜드 브루',
        children: [
          { type: 'item', name: '나이트로 콜드 브루' },
          { type: 'item', name: '돌체 콜드 브루' },
          { type: 'item', name: '제주 비자림 콜드 브루' },
          { type: 'item', name: '콜드 브루' },
        ],
      },
      {
        type: 'group',
        name: '프라푸치노',
        children: [
          { type: 'item', name: '애플 쿠키 크림 프라푸치노' },
          { type: 'item', name: '더블 에스프레소 칩 프라푸치노' },
          { type: 'item', name: '모카 프라푸치노' },
          { type: 'item', name: '피스타치오 크림 프라푸치노' },
        ],
      },
      {
        type: 'group',
        name: '블렌디드',
        children: [
          { type: 'item', name: '망고 바나나 블렌디드' },
          { type: 'item', name: '딸기 요거트 블렌디드' },
          { type: 'item', name: '자몽 셔벗 블렌디드' },
          { type: 'item', name: '피치 & 레몬 블렌디드' },
        ],
      },
      {
        type: 'group',
        name: '티',
        children: [
          { type: 'item', name: '라임 패션 티' },
          { type: 'item', name: '민트 블렌드 티' },
          { type: 'item', name: '아이스 유스베리 티' },
          { type: 'item', name: '아이스 캐모마일 블렌드 티' },
        ],
      },
      {
        type: 'group',
        name: '주스',
        children: [
          { type: 'item', name: '한방에 쭉 감당' },
          { type: 'item', name: '파이팅 청귤' },
          { type: 'item', name: '딸기주스' },
          { type: 'item', name: '도와주 흑흑' },
        ],
      },
    ],
  },
  {
    type: 'group',
    name: '음식',
    children: [
      {
        type: 'group',
        name: '빵',
        children: [
          { type: 'item', name: '트러플 미니 스콘' },
          { type: 'item', name: '보늬밤 몽블랑 데니쉬' },
          { type: 'item', name: '고소한 치즈 베이글' },
          { type: 'item', name: '미니 클래식 스콘' },
        ],
      },
      {
        type: 'group',
        name: '케이크',
        children: [
          { type: 'item', name: '밀당 에그 타르트' },
          { type: 'item', name: '마스카포네 티라미수 케이크' },
          { type: 'item', name: '블루베리 쿠키 치즈 케이크' },
          { type: 'item', name: '부드러운 생크림 카스텔라' },
        ],
      },
      {
        type: 'group',
        name: '샌드위치',
        children: [
          { type: 'item', name: '애플 까망베르 샌드위치' },
          { type: 'item', name: '트리플 머쉬룸 치즈 샌드위치' },
          { type: 'item', name: '로스트 치킨 샐러드 밀 박스' },
          { type: 'item', name: 'B.E.L.T 샌드위치' },
        ],
      },
      {
        type: 'group',
        name: '과일',
        children: [
          { type: 'item', name: '하루 한 컵 RED' },
          { type: 'item', name: '한라봉 가득 핸디 젤리' },
        ],
      },
      {
        type: 'group',
        name: '스낵',
        children: [
          { type: 'item', name: '리저브 초콜릿 세트' },
          { type: 'item', name: '로스티드 아몬드 앤 초콜릿' },
          { type: 'item', name: '마카롱' },
          { type: 'item', name: '자일리톨 캔디 크리스탈 민트' },
        ],
      },
      {
        type: 'group',
        name: '아이스크림',
        children: [
          { type: 'item', name: '자바 칩 유기농 바닐라 아이스크림' },
          { type: 'item', name: '넛츠 초콜릿 아포가토' },
          { type: 'item', name: '바닐라 아포가토' },
        ],
      },
    ],
  },
  {
    type: 'group',
    name: '굿즈',
    children: [
      {
        type: 'group',
        name: '머그',
        children: [
          { type: 'item', name: '우리 한글 블랙 머그 473ml' },
          { type: 'item', name: '서울 투어 머그 355ml' },
          { type: 'item', name: '스타벅스 1호점 머그 400ml' },
          { type: 'item', name: '서울 제주 데이머그 세트' },
        ],
      },
      {
        type: 'group',
        name: '텀블러',
        children: [
          { type: 'item', name: 'SS 부산 투어 텀블러 355ml' },
          { type: 'item', name: 'SS 블랙 헤리티지 오드리 텀블러 355ml' },
          { type: 'item', name: 'SS 에치드 실버 텀블러 473ml' },
        ],
      },
      {
        type: 'group',
        name: '악세사리',
        children: [
          { type: 'item', name: '리저브 오렌지 카드 홀더' },
          { type: 'item', name: '스타벅스 1호점 에코백' },
          { type: 'item', name: '스타벅스 1호점 랩탑 파우치' },
        ],
      },
    ],
  },
  {
    type: 'group',
    name: '카드',
    children: [
      { type: 'item', name: '10000원권' },
      { type: 'item', name: '30000원권' },
      { type: 'item', name: '50000원권' },
      { type: 'item', name: '100000원권' },
    ],
  },
];

문제목표 : menu의 배열을 아래와 같이 뿌려주는 것이다.

 <body>
    <ul id="root">
      <li>
        <input type="checkbox" checked />
        <span>음료</span>
        <ul>
          <li>
            <input type="checkbox" />
            <span>콜드브루</span>
            <ul>
              <li>나이트로 콜드 브루</li>
              <li>돌체 콜드 브루</li>
              <li>제주 비자림 콜드 브루</li>
              <li>콜드 브루</li>
            </ul>
          </li>
          <li>
            <input type="checkbox" />
            <span>프라푸치노</span>
            <ul>
              <li>애플 쿠키 크림 프라푸치노</li>
              <li>더블 에스프레소 칩 프라푸치노</li>
              <li>모카 프라푸치노</li>
              <li>피스타치오 크림 프라푸치노</li>
            </ul>
          </li>
          <li>
            <input type="checkbox" />
            <span>블렌디드</span>
            <ul>
              <li>망고 바나나 블렌디드</li>
              <li>딸기 요거트 블렌디드</li>
              <li>자몽 셔벗 블렌디드</li>
              <li>피치 & 레몬 블렌디드</li>
            </ul>
          </li>
          <li>
            <input type="checkbox" />
            <span></span>
            <ul>
              <li>라임 패션 티</li>
              <li>민트 블렌드 티</li>
              <li>아이스 유스베리 티</li>
              <li>아이스 캐모마일 블렌드 티</li>
            </ul>
          </li>
          <li>
            <input type="checkbox" />
            <span>주스</span>
            <ul>
              <li>한방에 쭉 감당</li>
              <li>파이팅 청귤</li>
              <li>딸기주스</li>
              <li>도와주 흑흑</li>
            </ul>
          </li>
        </ul>
      </li>
      <li>
        <input type="checkbox" />
        <span>음식</span>
        <ul>
          <li>
            <input type="checkbox" />
            <span></span>
            <ul>
              <li>트러플 미니 스콘</li>
              <li>보늬밤 몽블랑 데니쉬</li>
              <li>고소한 치즈 베이글</li>
              <li>미니 클래식 스콘</li>
            </ul>
          </li>
          <li>
            <input type="checkbox" />
            <span>케이크</span>
            <ul>
              <li>밀당 에그 타르트</li>
              <li>마스카포네 티라미수 케이크</li>
              <li>블루베리 쿠키 치즈 케이크</li>
              <li>부드러운 생크림 카스텔라</li>
            </ul>
          </li>
          <li>
            <input type="checkbox" />
            <span>샌드위치</span>
            <ul>
              <li>애플 까망베르 샌드위치</li>
              <li>트리플 머쉬룸 치즈 샌드위치</li>
              <li>로스트 치킨 샐러드 밀 박스</li>
              <li>B.E.L.T 샌드위치</li>
            </ul>
          </li>
          <li>
            <input type="checkbox" />
            <span>과일</span>
            <ul>
              <li>하루 한 컵 RED</li>
              <li>한라봉 가득 핸디 젤리</li>
            </ul>
          </li>
          <li>
            <input type="checkbox" />
            <span>스낵</span>
            <ul>
              <li>리저브 초콜릿 세트</li>
              <li>로스티드 아몬드 앤 초콜릿</li>
              <li>마카롱</li>
              <li>자일리톨 캔디 크리스탈 민트</li>
            </ul>
          </li>
          <li>
            <input type="checkbox" />
            <span>아이스크림</span>
            <ul>
              <li>자바 칩 유기농 바닐라 아이스크림</li>
              <li>넛츠 초콜릿 아포가토</li>
              <li>바닐라 아포가토</li>
            </ul>
          </li>
        </ul>
      </li>
      <li>
        <input type="checkbox" />
        <span>굿즈</span>
        <ul>
          <li>
            <input type="checkbox" />
            <span>머그</span>
            <ul>
              <li>우리 한글 블랙 머그 473ml</li>
              <li>서울 투어 머그 355ml</li>
              <li>스타벅스 1호점 머그 400ml</li>
              <li>서울 제주 데이머그 세트</li>
            </ul>
          </li>
          <li>
            <input type="checkbox" />
            <span>텀블러</span>
            <ul>
              <li>SS 부산 투어 텀블러 355ml</li>
              <li>SS 블랙 헤리티지 오드리 텀블러 355ml</li>
              <li>SS 에치드 실버 텀블러 473ml</li>
            </ul>
          </li>
          <li>
            <input type="checkbox" />
            <span>악세사리</span>
            <ul>
              <li>리저브 오렌지 카드 홀더</li>
              <li>스타벅스 1호점 에코백</li>
              <li>스타벅스 1호점 랩탑 파우치</li>
            </ul>
          </li>
        </ul>
      </li>
      <li>
        <input type="checkbox" />
        <span>카드</span>
        <ul>
          <li>10000원권</li>
          <li>30000원권</li>
          <li>50000원권</li>
          <li>100000원권</li>
        </ul>
      </li>
    </ul>
  </body>
</html>
  • 풀이


(1) ul#root 엘리먼트가 존재해야 합니다0ms ‣

  • const root = document.getElementById('root');
    getElementById를 통해서 root문자열과 일치하는 id속성을 찾고, 이를 나타내는 엘리먼트를 반환한다.

(2) ul#root 엘리먼트 안에 tree view를 구현해야 합니다0ms ‣

  • 자식구조를 가지게 만들어 주면된다.

(1) ul#root 엘리먼트 안에 카테고리(음료, 음식, 굿즈, 카드)를 렌더링할 4개의 li 엘리먼트가 있어야 합니다0ms ‣

  • 재귀함수를 통해서 menu라는 배열에 가장 큰요소 4개에 li tag를 달아주기 위해서 , 반복문을 통해서 돌린다.
    for(let i=0; i<menu.length; i++){
    const li = document.createElement('li')
    }

(2) 카테고리(음료, 음식, 굿즈, 카드) 엘리먼트 안에는 각각 자식 노드를 보여주고 감춰줄 checkbox가 존재해야 합니다0ms ‣


  • 이러한 체크 박스가 존재 하게 만들어야 하는 것이다.
    그러기 위해서 아래에 자식노드가 있는경우와 없는경우를 기준으로 나누어 준다.
    if(Object.keys(menu[i]).includes('children')) === if(menu[i].children)
    children이라는 키가 있으면,
    const input = document.createElement('input');
    input.type = 'checkbox' // 타입을 체크박스로 정해줘야 이렇게 적용됩니다.
    이렇게 인풋 박스를 만들어 줍니다.

(3) 음료, 음식, 굿즈, 카드 카테고리 이름(name)을 span 태그로 감싸야 합니다0ms ‣

  • const span = document.createElement('span')
    span.textContent = menu[i].name

(4) 자식 노드가 없는 데이터의 경우, li 엘리먼트 안에 단순히 이름(name)만 표시합니다. (checkbox 및 span, ul을 포함하면 안됩니다)1ms ‣
(7) type 속성이 item인 객체는 li 태그로 name 속성값을 감싸주어야 합니다0ms ‣

  • else{
    li.textContent = menu[i].name
    currentNode.append(li)
    }
    }
    type 속성이 item인 객체는 자식요소가 없는 객체이다. 재귀함수를 쓰지 않고 끝내준다.

(5) 자식 노드가 있는 데이터의 경우, li 엘리먼트 아래에 자식 노드를 렌더링할 새로운 ul이 존재해야 합니다 (1)0ms ‣
(6) 자식 노드가 있는 데이터의 경우, li 엘리먼트 아래에 자식 노드를 렌더링할 새로운 ul이 존재해야 합니다 (2)0ms ‣

  • const ul = document.createElement('ul')
    li.append (input, span, ul) 이런식으로 어팬드를 해준다.

      <li>
         <input type="checkbox" />
         <span>굿즈</span>
         <ul>
           <li>
             <input type="checkbox" />
             <span>머그</span>
             <ul>

    currentNode.append(li)
    createTreeView(menu[i].children, ul)
    자식노드가 있는 경우는 재귀를 통해 계속 돌려준다.

작성 코드

const root = document.getElementById('root');
function createTreeView(menu, currentNode) {
  for(let i=0; i<menu.length; i++){
    const li = document.createElement('li')
    if(Object.keys(menu[i]).includes('children')) {
      const input = document.createElement('input');
      input.type = 'checkbox'
      const span = document.createElement('span')
      span.textContent = menu[i].name
      const ul = document.createElement('ul')
      li.append (input, span, ul)
      currentNode.append(li)

      createTreeView(menu[i].children, ul)
    }else{
      li.textContent = menu[i].name
      currentNode.append(li)
    }
  }
  // TODO: createTreeView 함수를 작성하세요.
}

createTreeView(menu, root);

출처 : 코드스테이츠

profile
끝까지 ... 가면 된다.

0개의 댓글