이전 시간의 이벤트 핸들링에 이어 Vue.js의 이벤트 수식어에 대해 알아봅시다. 더욱 자세한 사항은 공식 문서를 참고해주시기 바랍니다.
이벤트 핸들러 내부에서 event.preventDefault()
또는 event.stopPropagation()
를 호출하는 것은 매우 보편적인 일입니다. 메소드 내에서 쉽게 이 작업을 할 수 있지만, DOM 이벤트 세부 사항을 처리하는 대신 데이터 로직에 대한 메소드만 사용할 수 있으면 더 좋습니다.
이 문제를 해결하기 위하여, Vue는 v-on
이벤트에 이벤트 수식어를 제공합니다. 수식어는 점으로 된 접미사 입니다.
.stop
.prevent
.capture
.self
.once
.passive
<!-- 클릭 이벤트 전파가 중단되었습니다. -->
<a @click.stop="doThis"></a>
<!-- 제출 이벤트가 페이지를 다시 로드하지 않습니다. -->
<form @submit.prevent="onSubmit"></form>
<!-- 수정자는 체이닝이 가능합니다. -->
<a @click.stop.prevent="doThat"></a>
<!-- 단순히 수식어만 사용이 가능합니다. -->
<form @submit.prevent></form>
<!-- 캡처 모드를 사용할 때 이벤트 리스너를 사용 가능합니다.-->
<!--즉, 내부 엘리먼트를 대상으로 하는 이벤트가 해당 엘리먼트에서 처리되기 전에 여기서 처리합니다. -->
<div @click.capture="doThis">...</div>
<!-- event.target이 엘리먼트 자체인 경우에만 트리거를 처리합니다.-->
<!-- 자식 엘리먼트에서는 처리되지 않습니다.-->
<div @click.self="doThat">...</div>
아래의 코드에서 child
의 요소를 클릭하게 되면, child에 정의된 이벤트 핸들러인 handlerB
메소드만 실행되는 것이 아니라 이를 포함하고 있는 부모 요소인 parent의 메소드도 함께 실행됩니다.
자식 요소를 클릭하면 결국 이를 포함하고 있는 부모 요소를 클릭하는 것과 마찬가지로 위의 요소를 타고 타고 올라가서 전파를 한다는 의미로 이를 이벤트 버블링이라고 부릅니다.
<template>
<div
class="parent"
@click="handlerA">
<div
class="child"
@click.stop="handlerB">
</div>
</div>
</template>
<script>
export default {
methods: {
handlerA() {
console.log('A') // 'B' 다음으로 'A' 출력
},
handlerB() {
console.log('B') // 자식 요소 클릭 시, 먼저 'B' 출력
}
}
}
</script>
이러한 이벤트 버블링을 방지하기 위해서 DOM event인 event.stopPropagation()
를 이용하는 방법도 있지만, 위와 같이 보다 더 간편하게 이벤트 수식어인 .stop
을 이용할 수도 있습니다.
이벤트 캡쳐링은 위의 이벤트 버블링과 반대되는 개념입니다. 바로 부모 요소에서 자식 요소로 내려오는 개념입니다. 위의 주석에 표시한 것처럼, 자식 요소를 클릭하게 되면 자식 요소의 메소드가 먼저 실행되고 이후에 부모의 메소드가 실행되게 됩니다.
이를 위해 부모 요소에 .capture
라는 이벤트 수식어를 적용하면 반대로 부모 요소의 메소드 다음 자식의 메소드가 실행되게 됩니다. 추가적으로 자식 요소를 클릭해도 부모의 메소드인 'A'만 출력되길 원한다면, @click.capture.stop
처럼 메소드 체이닝을 적용하면 됩니다.
<template>
<div
class="parent"
@click.capture="handlerA">
<div
class="child"
@click="handlerB">
</div>
</div>
</template>
또한 Vue는 addEventListener
의 passive
옵션에 해당하는 .passive
수식어도 제공합니다. 이를 통해, 화면의 구현과 이에 해당하는 로직이 브라우저가 동시에 처리하기 때문에 로직이 복잡하고 양이 많다면 그만큼 부하가 발생하게 되니다.
.passive
라는 이벤트 수식어는 로직의 처리와 화면의 동작을 완전히 독립시켜 주게 됩니다. 이를 통해 부하를 줄일 수 있게 되는 것입니다. 화면은 부드러워보이지만, 로직은 매우 열심히 돌아가고 있는 구조가 되는 것입니다.
<!-- 스크롤의 기본 이벤트를 취소할 수 없습니다. -->
<!-- 바로, `onScroll`완료되는 것을 기다리는 것을 대신합니다. -->
<!-- 이 경우에`event.preventDefault()`를 포함하고 있습니다. -->
<div @scroll.passive="onScroll">...</div>
특히 .passive
수식어는 모바일 환경에서 성능향상에 도움이 됩니다.
유의해야할 점은 .prevent
수식어는 무시되고 브라우저에서 오류를 발생시키기 때문에, .passive
수식어와 .prevent
수식어를 함께 사용하시면 안됩니다. .passive
수식어는 이벤트의 기본 행동을 무시하지 않기를 원하는 브라우저와 상호작용하기 때문입니다.