프로젝트를 진행하다 보면 커스텀 컴포넌트를 직접 제작할 일이 매우 빈번하게 일어납니다.
그리고 이런 커스텀 컴포넌트 중 영역 외부 클릭 이벤트를 적용해야 하는 경우도 있죠. 예를 들면 드롭다운이 이러한 형태에 속합니다.
드롭다운은 누르면 펼쳐지고 다시 누르면 닫히게 되는데 사용자가 드롭다운 버튼을 통해서만 열린 드롭다운을 닫아야 한다면 다소 불편한 경험을 안겨줄 수 있을 것입니다.
이럴 때 사용하면 좋은 녀석 중 하나가 click-outside-vue3
라이브러리입니다.
비슷한 기능을 제공하는 패키지들이 여럿 있겠지만, 저는 click-outside-vue3
를 통해서 엘리먼트 외부 클릭에 대한 처리를 편하게 했습니다.
설치
터미널에서 아래 명령어를 입력하여 패키지를 설치합니다.
npm
npm install --save click-outside-vue3
yarn
yarn add click-outside-vue3
사용하기
main.js
import { createApp } from 'vue';
import App from './App.vue';
import vClickOutside from 'click-outside-vue3'; // click-outside-vue3 패키지를 임포트합니다.
createApp(App).use(vClickOutside).mount('#app'); // .use(vClickOutside) 로 전역 사용하도록 추가해 줍니다.
먼저 click-outside-vue3
패키지를 import한 후, createApp(App).use(vClickOutside)
를 통해 해당 라이브러리를 사용하겠다고 선언해 줍니다.
그리고 mount('#app')
을 통해 마운트해 주면 됩니다.
이 라이브러리 뿐만 아니라 다른 라이브러리를 전역적으로 임포트해서 사용할 때는 마찬가지로 .use(이름)
을 연속적으로 체이닝해서 사용해도 됩니다.
App.vue (대상 컴포넌트)
<template>
<div>
<button type="button" @click="toggleDropdown" v-click-outside="vcoConfig">Dropdown</button>
<ul class="dropdown" v-show="isDropdownOpen">
<li class="dropdown-item">Dropdown item</li>
<li class="dropdown-item">Dropdown item</li>
<li class="dropdown-item">Dropdown item</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
isDropdownOpen: false,
vcoConfig: {
handler: this.hideDropdown, // config 를 통해 이벤트 핸들러를 직접 지정
middleware: this.middleware, // 클릭된 요소가 특정 기능을 수행할 경우 이벤트 전파를 막기 위한 middleware 설정
events: ['click'], // 적용 이벤트 (dblclick 도 있음)
isActive: true, // v-click-outside 활성화 여부 (기본값 true)
detectIFrame: true, // iframe 감지 여부 (기본값 true)
capture: false // 대상 EventTarget의 addEventListener메서드에 영향을 준다.
// 특정 이벤트 핸들러가 stopPropagation 메서드를 통해 이벤트 버블링을 방지하고자 할 때 유용할 수 있다.
}
}
},
methods: {
toggleDropdown() {
this.isDropdownOpen = !this.isDropdownOpen;
},
hideDropdown() {
this.isDropdownOpen = false;
},
// middleware는 지정된 요소의 바깥을 클릭할 시에 발동된다.
// 이 함수는 반드시 함수를 통해서만 실행이 가능하며 Boolean 타입으로 값을 리턴해야 반환된 true / false 값에 따라
// middleware 핸들러가 작동하게 된다.
// 아래 예시는 특정 기능을 수행할 가능성이 매우 높은 dropdown-item 이라는 클래스를 가진 요소를
// middleware로 지정함으로써 해당 요소에 걸려 있는 이벤트가 실행 불가능하게 되는 상황을 방지하는 것이다.
middleware(event) {
return event.target.className === 'dropdown-item'
}
}
}
</script>
위 소스는 커스텀 드롭다운을 예시로 작성해본 것입니다.
드롭다운을 열어주는 button
에 v-click-outside
속성을 통해 vcoConfig
를 바인딩시킵니다.vcoConfig
는 아래 스크립트에 보시면 data() { ... } 내에서 정의되고 있습니다.
v-click-outside 패키지에서 지원하는 config 옵션들과 그에 대한 설명을 주석으로 표기하였습니다.
여기서 주의깊게 살펴볼 것은, vcoConfig
안의 middleware: this.middleware
와 methods
에 정의되어 있는 middleware(event) { .. }
부분입니다.
별도로 middleware
를 지정하지 않으면 v-click-outside
속성이 지정되어 있는 button
엘리먼트 바깥 영역이라면 그 어디를 눌러도 드롭다운 컴포넌트가 닫힐 것입니다.
단순히 이것만 생각한다면 문제가 없다고 보여질 수 있습니다. 하지만 대개는 드롭다운 안에 있는 자손 링크들이 특정 동작을 수행하는 경우가 많은데 이 자손 링크에 부여되어 있는 이벤트 핸들러가 모두 무시된다는 치명적인 현상이 발생하게 됩니다.
따라서 middleware
를 통해서 사용자가 클릭한 엘리먼트의 클래스명이 dropdown-item
인 녀석을 여기에 대응시켜 줌으로써 드롭다운의 자손 링크인 <li class="dropdown-item">...</li>
이 의도한 동작을 성공적으로 수행시킬 수 있도록 해주는 것입니다.
'웹개발 > Vue' 카테고리의 다른 글
Vue 3 + Vite 환경에서 Tailwind CSS 설치하기 (0) | 2024.02.05 |
---|---|
Vue 3 + Vite 환경에서 SCSS 전역적으로 사용하는 방법 (0) | 2024.01.21 |