[js, jquery]accordion toggle

blue·2022년 12월 9일
0

js

목록 보기
1/9


오늘은 아코디언을 jquery와 js로 각각 작성하는 방법을 알아보자!

html

  <div class="accordian-wrap">
          <div class="accordian">
            <p>Q. 참가 신청만 제출하면 참가 완료인가요?</p>
            <i class="btn-more"></i>
          </div>
          <div class="pannel">
            <p>참가 신청서 제출 후 7일 이내로 기입하신 이메일이나 연락처로 참가 가능 여부에 대한 결과를 안내드릴 예정입니다.<br>주최측으로부터 참가에 대한 최종 안내 연락을 받으신 분에 한해서 참가가 가능합니다.</p>
          </div>
        </div>


html은 질문인 p태그와 btn-more을 감싸는 accordian,
답변 pannel영역을 감싸는 accordian-wrap 구조로 작성하였다.

공통 css

   .accordian-wrap {
    display: flex;
    flex-direction: column;
    margin-bottom: 2rem;
  }
  .accordian {
    display: flex;
    align-items: center;
    position: relative;
    width: 100%;
    height: 10rem;
    padding: 0 4rem;
    border-radius: 10px;
    background: #eee;
    transition: .4s;
    cursor: pointer;
    /* js 
    btn-more에서 바로 바꿔주는게 아니라
    accordian.on에서 btn-more을 바꿔줘야함!
    */ 
    &.on {
      border-radius: 10px 10PX 0 0;
      .btn-more {
        background-color: #bbbbbb;
        &::before {
          display: none;
        }
      }
    }
    p {
      max-width: 90%;
      font-size: 2.8rem;
      word-break: break-all;
    }
    .btn-more {
      position: absolute;
      right: 4rem;
      width: 5rem;
      height: 5rem;
      background-color: #0500fd;
      border-radius: 100%;
      transition: .3s;
      // 요기 아님 
      // &.on {
      //   background-color: #bbbbbb;
      // }
      &::before {
        content: '';
        display: inline-block;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: .3rem;
        height: 3.2rem;
        background: #fff;
      }
      &::after {
        content: '';
        display: inline-block;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 3.2rem;
        height: .3rem;
        background: #fff;
      }
    }
  }

accordian 속 text는 max-width를 %로 설정해놓고,
button 영역은 침범하지 않도록 한다.
button은 position으로 위치잡음

btn-more에서 바로 on 클라스를 더해주는 것이 아니라,
accordian.on에서 btn-more이 변경될 수 있도록 작성해야 함!

🥺 issue 발생!
text와 button을
display:flex & justify-content: space-between;로
text는 width를 잡지 않았을 때,
button과 text가 겹치는 현상 발생!

📌jquery

✅ css (pannel)

  .pannel {
    display: none;
    margin-top: -1rem;
    margin-bottom: 1rem;
    border: 2px solid #eee;
    border-radius: 0 0 10px 10px;
    background: #fff;
    // jquery
    &.on {
      display: block;
    }
    p {
      padding: 4rem 8rem;
      font-family: "Noto Sans KR";
      line-height: 1.545;
      font-size: 2.2rem;
      font-weight: 300;
    }
  }

✅ jquery

    $('.accordian').click(function(){
    
        const siblings = $(this).siblings('.pannel')
        const children = $(this).children('.btn-more')
        
        siblings.slideToggle();
        children.toggleClass('on');
        $(this).toggleClass('on');
    })

📝 공부 과정

jquery 와 js css가 살짝 다르다...

css
pannel 초기에는 display : none으로 설정해두고,
on class가 실행되었을 때,
block 으로 보이도록 설정하였다.
(transition은 별도로 설정하지 않아도 부드럽게 작동한다..!)

jquery
간략하게 말하자면 display :block과 none로 pannel을 다룬다.

우선, accordian을 클릭할 때, 이벤트가 실행되도록 먼저 변수 선언이 필요했다.
accordian의 형제인 pannel을 siblings로 선언,
자식요소인 btn-more을 children으로 선언했다.

우선, 답변 영역(pannel)에 slideToggle을 걸어주었고,
btn-more과 accordian에 css로 작성한 "on" toggleClass가 작동되도록 걸어주었다.
(문제는 js..😇)



📌js

✅ css (pannel)

  .pannel {
    overflow: hidden;
    height: 0;
    margin-top: -1rem;
    margin-bottom: 1rem;
    border: 2px solid #eee;
    border-radius: 0 0 10px 10px;
    background: #fff;
    transition: height 0.2s ease-out;
    p {
      padding: 4rem 8rem;
      font-family: "Noto Sans KR";
      line-height: 1.545;
      font-size: 2.2rem;
      font-weight: 300;
    }
  }

✅ js

const acc = document.querySelectorAll(".accordian");

for (i = 0; i < acc.length; i++) {
    acc[i].addEventListener("click", function () {

        this.classList.toggle("on");
        const panel = this.nextElementSibling;

        if (panel.style.height) {
            panel.style.height = null;
        } else {
            panel.style.height = panel.scrollHeight + "px";
        }
    });
}

1) acc[i] : 1.list를 나열 할 2.list의 인덱스를 지정해줄 때 ex) mise[0], mise[1]
2) classList.toggle은 클래스의 유무를 체크해서 없으면 add, 있으면 remove를 자동으로 시켜준다.
3) nextElementSibling : "다음 요소를 선택하고 싶다"
=> "accordian"의 다음 요소인 "pannel"(텍스트 제외)

📝 공부 과정

우선, 아코디언의 height을 0px → 148px로 조절되도록 하는 것이 제일 중요했다!

아코디언이 올라갔다 내려갔다는 되는데 버튼이 바뀌지않는 시행착오를 겪었다...
accordian을 눌렀을 때, on클라스가 더해진 상태에서 btn이 바뀌도록 css를 설정했었어야 함!

💚참고 사이트
#source :
https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_accordion_symbol
#classList, #toggle :
https://hyunjungchoi.tistory.com/70
#nextElementSibling vs nextSibling : https://aljjabaegi.tistory.com/548

2개의 댓글

comment-user-thumbnail
2024년 2월 28일

선생님 안녕하세요!! 궁금하게 있어서 댓글 달아봅니다!
아코디언 메뉴가 3개 있다고 가정 했을 때 1개만 열려있는 상태로 구현도 가능한가요?ㅠㅜ

1개의 답글