ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • React / 아코디언 메뉴 만들기
    Web dev/React 2022. 3. 30. 18:22
    728x90
    반응형

    리엑트로 퍼블리싱중 사이드바를 구현하면서 아코디언을 구현해봤다.

    제이쿼리를 쓰면 편하겠지만 제이쿼리를 안쓰려고 노력중이다.

     

    처음엔 tab을 만들어본적이 있어서 useState를 사용해 구현해보려햇는데 젠장 다같이 동작해서 망했다 

    그렇다고 각메뉴에 useState를 사용하면 오히려 더 지저분해질것 같아서 그냥 구현해보았다.

    w3school를 참조했다.

     

    1. for문을 돌려 각 리스트에 번호를 메긴뒤 그것이 클릭되면 이벤트를 주었다.

       제이쿼리에 길들여져 그냥 구현하라 했으면 못했을것같다. 코린이는 웁니다...

       여기서 문제는 예제는 this로 셀렉을 하던데 나는 이상하게 못가져오는것이다.. 

       자바스크립트 this는 어려워..

       e.target으로 하니까 잘가져온다. useEffect로 로드 되었을때 한번 동작시켜줘야 잘 가져온다.

    useEffect(() =>{
      let listTitle = document.getElementsByClassName(aside.list_title);
      let i;
    
      for (i = 0; i < listTitle.length; i++) {
        listTitle[i].addEventListener("click", (e) => {
          e.target.classList.toggle(aside.checked);
          let listItem = e.target.nextElementSibling;
          if (listItem.style.maxHeight) {
            listItem.style.maxHeight = null;
          } else {
            listItem.style.maxHeight = listItem.scrollHeight + "px";
          }
        });
      }
    },[])

     

    슬라이딩으로 해야 이쁘기 때문에 조건문 스타일을 변형해준다.

    제이쿼리에선 슬라이드다운,업,토글 하면 되는데 이렇게 하는것도 신기했다. 뭔가 멋지다

     

    <Aside.jsx>

    import React, { useEffect } from 'react'
    import { Link } from 'react-router-dom';
    import aside from '../../assets/css/common/aside.module.css'
    
    import useLoginCheck from '../Hook/useLoginCheck';
    
    export default function Aside() {
    
    useEffect(() =>{
      let listTitle = document.getElementsByClassName(aside.list_title);
      let i;
    
      for (i = 0; i < listTitle.length; i++) {
        listTitle[i].addEventListener("click", (e) => {
          e.target.classList.toggle(aside.checked);
          let listItem = e.target.nextElementSibling;
          if (listItem.style.maxHeight) {
            listItem.style.maxHeight = null;
          } else {
            listItem.style.maxHeight = listItem.scrollHeight + "px";
          }
        });
      }
    },[])
    
      return (
        <>
          <div className={aside.deemed}></div>
          <div className={aside.aside_btn} onClick={handleAide}>
            <img src="/assets/images/aside_btn.png" alt="" />
          </div>
          <div className={aside.aside_wrap}>
            <div className={aside.close_btn} onClick={handleClose}>
              <img src="/assets/images/close.png" alt="" />
            </div>
            <div className={aside.inner}>
              <ul className={aside.list}>
                  <li>
                    <div className={aside.list_title}>
                      <div><button>쇼핑</button><span>shopping</span></div>
                      <span className={aside.list_title_icon}></span>
                    </div>
                    <ul className={aside.list_item}>
                      <li><Link to='/'>전체보기</Link></li>
                      <li><Link to='/'>베스트</Link></li>
                      <li><Link to='/'>신상품</Link></li>
                      <li><Link to='/'>라인별</Link></li>
                    </ul>
                  </li>
                  <li>
                    <div className={aside.list_title}>
                      <div><button>브랜드</button><span>brand</span></div>
                      <span className={aside.list_title_icon}></span>
                    </div>
                    <ul className={aside.list_item}>
                      <li><Link to='/'>브랜드 소개</Link></li>
                    </ul>
                  </li>
                  <li>
                    <div className={aside.list_title}>
                      <div><button>이벤트</button><span>event</span></div>
                      <span className={aside.list_title_icon}></span>
                    </div>
                    <ul className={aside.list_item}>
                      <li><Link to='/'>진행중인 이벤트</Link></li>
                      <li><Link to='/'>지난 이벤트</Link></li>
                    </ul>
                  </li>
                  <li>
                    <div className={aside.list_title}>
                      <div><button>리뷰</button><span>review</span></div>
                      <span className={aside.list_title_icon}></span>
                    </div>
                    <ul className={aside.list_item}>
                      <li><Link to='/'>리뷰</Link></li>
                      <li><Link to='/'>포토리뷰</Link></li>
                    </ul>
                  </li>
                  <li>
                    <div className={aside.list_title}>
                      <div><button>스토리</button><span>story</span></div>
                      <span className={aside.list_title_icon}></span>
                    </div>
                    <ul className={aside.list_item}>
                      <li><Link to='/'>제품스토리</Link></li>
                      <li><Link to='/'>소셜채널</Link></li>
                    </ul>
                  </li>
              </ul>
            </div>
          </div>
        </>
      )
    }

     

     

    리스트가 열렸을때 클래스를 주는것보다 플러스,마이너스 버튼은 CSS관리 해줘야 편하다.

    잘 모를땐 이미지를 2개넣고 상태에따라 display:none 처리를 해주었는데 백그라운드이미지로 저렇게 바꿔주는게 개꿀 ㅎㅎ

    URL 부분 뭔가 지저분하다 변수로 관리하면 더 좋을것 같다. 나중에 적용해봐야지

    .list_title .list_title_icon{
        display: inline-block;
        width: 14px;
        height: 14px;
        box-sizing: border-box;
        background-image: url(../../../../public/assets/images/btn_plus.png); 
        background-repeat: no-repeat;
        background-size: cover;   
    }
    .list_title.checked .list_title_icon{
        background-image: url(../../../../public/assets/images/btn_minus.png) !important; 
    }

     

     

    귀찮아서 코드전체다 올릴라다가 포스팅 내용만 짤라서 올릴려니까 뭔가 빼먹은것 같기도하고 ..

    나만 볼꺼니 상관없당.

     

    <aside.module.css>

    .aside_wrap{
        width: 500px;
        position: fixed;
        top: 0;
        bottom: 0;
        right: 0;
        z-index: 99;
        background-color: #fff;
        transition: all 0.6s ease;
    }
    .inner{
        width: 90%;
        margin: 0 auto;
    }
    .list_title{
        display: flex;
        justify-content: space-between;
        align-items: center;
        border-bottom: 1px solid #eee;
        padding: 10px 0;
        cursor: pointer;
    }
    .list_title .list_title_icon{
        display: inline-block;
        width: 14px;
        height: 14px;
        box-sizing: border-box;
        background-image: url(../../../../public/assets/images/btn_plus.png); 
        background-repeat: no-repeat;
        background-size: cover;   
    }
    .list_title.checked .list_title_icon{
        background-image: url(../../../../public/assets/images/btn_minus.png) !important; 
    }
    
    .list_title button{
        font-size: 16px;
        font-weight: 700;
        color: #222;
        letter-spacing: 0.02vw;
    }
    .list_title span{
        margin-left: 10px;
        font-size: 12px;
        font-weight: normal;
        color: #8f8f8f;
        text-transform: uppercase;
    }
    .list_item{
        border-bottom: 1px solid #eee;
        max-height: 0;
        overflow: hidden;
        transition: max-height 0.2s ease-out;
        box-sizing: border-box;
    }
    .list_item li{
        display: block;
        padding: 5px;
    }
    .list_item li:first-child{
        margin-top: 10px;;
    }
    .list_item li:last-child{
        margin-bottom: 10px;;
    }
    .list_item li a{
        display: block;
        font-size: 14px;
        color: #555;
        font-weight: 400;
    }

    728x90
    반응형

    댓글

Designed by Tistory.