- DOM ref
- event.target
- <transition></transition>
오늘은 지난 시간에 이어서 vue에서 만든 아코디언 메뉴를 부드럽게 하는 방법에 대해서 알아보겠습니다.
앞 시간 요약
v-for 반복문으로 생성한 아코디언 컨텐츠들에 상태값(isOpen)을 독립적으로 설정해두고 개별적으로 열고 닫고 상태를 컨트롤 한다.
오늘 작업 포인트
1. 부드럽게 open할 요소를 ref 또는 event.target 으로 select한다.
2. v-show를 사용하면 요소가 display none/block 처리되기 때문에 요소를 컨트롤 하기 전에는 반드시 요소를 display:block 처리해준다.
오늘 탭을 부드럽게 열고 닫는 기능에서는 v-show 디렉티브를 사용할건데요 간단하게 v-if와 v-show의 차이에 대해서 알고 넘어가자면
v-show
실제 돔이 화면에 그려진 상태에서
display만 none 또는 block 처리 됨.
v-if
화면에 돔이 존재하지 않다가
조건에 의해서 렌더링 되고 제거됨.
위에 두 디렉티브의 큰 차이점을 말씀드렸는데요 추가적으로는 v-if가 돔을 붙였다 제거했다 하는 방식이라 v-show에 비해서 렌더링 속도면에서 더 느리며 돔을 그리고 삭제하는 조건이 자주 발생하는 경우에 성능 측면에서 불리할 수 있습니다.
그렇기 때문에 조건이 자주 바뀌는 자주 사용이되는 영역에서는 v-show가 더 적절한 사용이 될 수 있다고 보시면 됩니다. (v-if를 사용해서 컨텐츠를 부드럽게 오픈하는 방법도 나중에 알아보도록 하겠습니다)

서론이 길었네요🥲
<transition>을 사용할 경우 더욱 편리하게 기능을 구현할 수 있는데요 이것과 더불어 그냥 스크립트를 사용하는 방법도 같이 알아볼거에요. 아래 css는 이번 기능을 적용하 위한 박스의 초기상태 css입니다. 높이를 0으로 설정해두어야 열리는 효과를 줄 수 있어요
/* 기능적용을 위해 초기 설정해야 하는 css */
.cont{
overflow: hidden; /* 상황에 따라 줌 */
height:0px; /* 열리기 전에 초기 높이를 0으로 설정 */
transition: all .3s ease; /* 부드러운 효과를 위해 트랜지션 줌 */
}
Ref Dom 참조
먼저 ref 를 활용해 dom을 참조해서 만들어볼게요. ref는 반응형 변수를 생성할 수도 있지만 div 같은 요소에 접근할 수도 있습니다. 이런것을 Dom 접근 또는 dom 참조라고 하는데요 앞시간에는 단순히 v-if를 통해 dom을 그리고 지우고 처리를 했지만 이번에는 해당 요소를 컨트롤해야 하는 상황이기 때문에 소스가 약간 추가 변경되었습니다.
let contRefs = ref([]);
ref를 통해 dom에 접근할 것이기 때문에 다중으로 출력된 요소를 contRefs ref 배열로 담아주기 위해 변수를 먼저 생성했습니다.
<div
class="cont"
:ref="(el) => { if(el) contRefs[index] = el }"
v-show="item.isOpen"
>
// el은 현재 레벨의 element로 콜백함수의 인자이며 cont 자신을 의미한다.
// el이 존재하면 contRefs[index] 번째에 el 즉, cont div를 담는다
실제 코드에서는 반복문이 실행되는 코드 내에서 :ref 를 동적으로 생성해주었습니다.
이렇게 하면 v-for문으로 생성된 아코디언에 있는 .cont dom에 하나하나 ref로 접근을 했다고 생각하시면 됩니다.
동작 확인
아코디언 버튼을 누를 때 마찬가지로 isOpen이 true가 되는 경우 아코디언을 오픈해줄건데요 앞시간과 달리 단순히 오픈이 아닌 부드럽게 오픈을 해줄 것입니다.
오픈하는 코드는 아래의 순서대로 작성하게 됩니다.
- isOpen을 true로 설정
- cont 박스display를 block로 설정
- cont 박스 컨텐츠 높이만큼 cont박스를 오픈
<button
@click="itemOpen(item, index)"
>
{{ index+1 }}번 {{item.title}}
</button>
버튼을 클릭하면서 몇번째 요소가 클릭되었는지 구분하기 위해서 index를 같이 참조합니다. 아래의 실행문에서는 위 코드 실행 순번대로 실행문을 작성해줍니다.
const itemOpen = (item, index) => {
const el = contRefs.value[index];
if(!item.isOpen){
item.isOpen = true
el.style.display = 'block'
el.style.height = el.scrollHeight + 'px'
}else{
el.style.height = 0
setTimeout(() => {
item.isOpen = false
},300)
}
}
위 코드는 컨텐츠 박스를 오픈상태로 설정하고 컨텐츠 박스 내용의 높이만큼 cont박스를 펼쳐주는 내용의 코드입니다.
v-show 디렉티브를 사용하면서 가장 유의해야 할 점은 해당 요소가 화면에서 display none/block처리된다는 점입니다. 요소가 display none일 경우 dom컨트롤이 잘 되지 않기 때문에 컨트롤하기 전 반드시 display block처리해줘야 한다는 점은 유의해주세요
이제 완성된 코드를 보겠습니다.
위와 같이 아코디언이 부드럽게 펼쳐지고 닫히는 걸 확인하실 수 있습니다.
이번 시간에는 ref로 dom에 접근하는 방법으로 기능을 구현해보았는데요 vue 개발을 하는 입장에서는 ref 사용법을 익혀두는 것이 좋기 때문에 먼저 ref를 사용해보았는데요 반드시 ref를 사용해야 하는 것은 아니기 때문에 다음시간에는 이벤트 타겟으로 기능을 적용해보도록 하겠습니다.
이번 포스팅에서 다 하려고 했지만 생각보다 길어진 것 같아서 우선 줄이겠습니다.🥲
참고로 트렌지션 컴포넌트나 이벤트 타겟으로 작업하는 것이 훨씬 쉽고 간편하니 다음시간에는 더 쉽게 이해하실 수있을거라 생각합니다. 그럼 다음시간에 만나요👍
'프로그래밍 > vue.js' 카테고리의 다른 글
v-model을 이용한 Number Stepper 구현하기(vue3) (2) | 2025.05.27 |
---|---|
vue3 Transition 을 이용한 아코디언 기능(부드럽게 열고 닫기) (0) | 2025.05.19 |
vue3 아코디언 메뉴 부드럽게 열고 닫기 event.target (0) | 2025.05.10 |
vue3 아코디언 메뉴 컨텐츠 만들기(기능 구현) (7) | 2025.04.26 |
vue.js SPA(싱글 페이지 어플리케이션) 이란? (2) | 2025.04.12 |