오늘은 아코디언을 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>
공통 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가 겹치는 현상 발생!
.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;
}
}
$('.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..😇)
.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;
}
}
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
선생님 안녕하세요!! 궁금하게 있어서 댓글 달아봅니다!
아코디언 메뉴가 3개 있다고 가정 했을 때 1개만 열려있는 상태로 구현도 가능한가요?ㅠㅜ