v-on
디렉티브로 사용할 수 있다. 그리고 v-on
이벤트는 자주 사용하기 때문에 @
단축 표현으로 많이 사용된다.<template>
<div>
<button @click="printEventInfo('hello vue3', $event)">
inline event handler
</button>
<input tyle="text" @keyup="onKeyUpHandler" />
</div>
</template>
export default {
setup() {
const printEventInfo = (message, event) => {
console.log("message:", message);
console.log("event.target:", event.target);
console.log("event.target.tagName:", event.target.tagName);
};
const onKeyUpHandler = event => {
console.log("event.key:", event.key);
};
return {
printEventInfo,
onKeyUpHandler,
};
},
};
이렇게 button을 클릭하고 input에 키를 눌렀을 때 evnet.key에 의해 어떤 키가 눌렸는지 console에 값이 찍히는 걸 확인할 수 있다. Vue에서는 이렇게 이벤트 이름 앞에 v-on(@)
디렉티브를 사용함으로써 이벤트를 연결할 수 있다.
event.preventDefault()
또는 event.stopPropagation()
메서드를 호출할 수 있다. 메소드에서 이러한 메소드의 호출은 어렵지 않지만 메소드 안에서 비즈니스 외에 이러한 코드는 비효율적이다.event.preventDefault()
-> 기본 기능을 막는 메소드event.stopPropagation()
-> 이벤트 전파를 막는 메소드
.stop
=e.stopPropagation()
.prevent
=e.preventDefault()
.capture
= 캡쳐 모드를 사용할 때 이벤트 리스너를 사용 가능합니다.
.self
= 오로지 자기 자신만 호출할 수 있다. 즉 타깃요소가self
일 때 발동된다.
.once
= 해당 이벤트는 한 번만 실행된다.
.passive
= 일반적으로 모바일 장치의 성능을 개선 하기 위해 터치 이벤트 리스너와 함께 사용된다.
<template>
<div>
<div id="modifiers">
<div @click="clickDiv">
DIV 영역
<p @click="clickP">
P 영역
<span @click="clickSpan"> span 영역 </span>
</p>
</div>
</div>
</div>
</template>
export default {
setup() {
const clickDiv = () => {
console.log("clickDiv");
};
const clickP = () => {
console.log("clickP");
};
const clickSpan = () => {
console.log("clickSpan");
};
return {
clickDiv,
clickP,
clickSpan,
};
},
};
이 상태에서 span영역
을 클릭 했을 때 상황을 보자
이벤트 버블링(전파)으로 인해서 span영역
-> P 영역
-> DIV 영역
순으로 클릭 이벤트가 먹게 된다. 이렇게 겹쳐있는 순서대로 이벤트가 발생한다. 예를 들어 인스타를 가정으로 DIV 영역
을 클릭 시 상세페이지로 이동하며 span 영역
을 클릭 시 좋아요 버튼이라고 생각을 해보자
export default {
setup() {
const clickDiv = () => {
console.log("clickDiv");
location.href = "https://naver.com";
};
const clickP = () => {
console.log("clickP");
};
const clickSpan = () => {
console.log("clickSpan");
alert("좋아요");
};
return {
clickDiv,
clickP,
clickSpan,
};
},
};
이런 경우에 좋아요 버튼을 클릭 시 alert 이벤트가 먼저 발생하고 이벤트 전파로 인해 DIV 영역
의 상세페이지 이동까지 이벤트가 발생하는 걸 볼 수 있다. 이를 제어할 수 있는게 .stop = e.stopPropagation()
다.
<template>
<div>
<div id="modifiers">
<div @click="clickDiv">
DIV 영역
<p @click="clickP">
P 영역
<!-- 이벤트 전파를 막을 수 있다. -->
<span @click.stop="clickSpan"> span 영역 </span>
</p>
</div>
</div>
</div>
</template>
아래와 같은 이벤트다.
export default {
setup() {
const clickDiv = () => {
console.log("clickDiv");
location.href = "https://naver.com";
};
const clickP = () => {
console.log("clickP");
};
const clickSpan = e => {
console.log("clickSpan");
alert("좋아요");
e.stopPropagation();
};
return {
clickDiv,
clickP,
clickSpan,
};
},
};
<template>
<div>
<div id="modifiers">
<div @click="clickDiv">
DIV 영역
<p @click="clickP">
P 영역
<span @click.stop="clickSpan"> span 영역 </span>
</p>
</div>
</div>
<a href="https://naver.com" @click.prevent="clickA">a 영역</a>
</div>
</template>
위와 아래는 같다.
export default {
setup() {
const clickDiv = () => {
console.log("clickDiv");
location.href = "https://naver.com";
};
const clickP = () => {
console.log("clickP");
};
const clickSpan = () => {
console.log("clickSpan");
alert("좋아요");
};
const clickA = e => {
e.preventDefault();
alert("어떤기능");
};
return {
clickDiv,
clickP,
clickSpan,
clickA,
};
},
};
a 태그
의 기본 기능은 링크이동이다. 이 기본적인 기능을 막을 수 있는게 .prevent = e.preventDefault()
다. 위와 같이 둘 중 하나를 사용하면 링크이동의 기본 동작을 막으며 alert 창만 확인이 된다. 만약 a 태그
가 박스 안에 있으면 어떻게 될까?
<template>
<div>
<div id="modifiers">
<div @click="clickDiv">
DIV 영역
<p @click="clickP">
P 영역
<span @click.stop="clickSpan"> span 영역 </span>
<a href="https://naver.com" @click.prevent="clickA">a 영역</a>
</p>
</div>
</div>
</div>
</template>
이럴 경우 버블링으로 인해 a 영역
를 클릭 시 P 영역
-> DIV 영역
순으로 발생하여
a 태그
의 이벤트는 막았지만 DIV 영역
의 이벤트로 인해 네이버 페이지창이 열릴 것이다.
이럴경우 수식어를 연결해서 사용할 수 있다.
<template>
<div>
<div id="modifiers">
<div @click="clickDiv">
DIV 영역
<p @click="clickP">
P 영역
<span @click.stop="clickSpan"> span 영역 </span>
<a href="https://naver.com" @click.prevent.stop="clickA">a 영역</a>
</p>
</div>
</div>
</div>
</template>
span 영역
을 클릭 시 clickSpan -> clickP -> clickDiv 순으로 console에 찍히는 걸 볼 수 있다. 여기서 DIV 영역
에 .capture
이벤트를 줘보자<template>
<div>
<div id="modifiers">
<div @click.capture="clickDiv">
DIV 영역
<p @click="clickP">
P 영역
<span @click.stop="clickSpan"> span 영역 </span>
<a href="https://naver.com" @click.prevent.stop="clickA">a 영역</a>
</p>
</div>
</div>
</div>
</template>
클릭 시 clickDiv -> clickSpan -> clickP 순으로 버블링이 일어나는 걸 볼 수 있다.
캡쳐링 모드에서 버블링이 됐기 때문에 clickDiv를 먼저 실행하고 그 다음 버블링이 시작된다. 이벤트를 먼저 실행하여야 할 때 활용이 가능하다.
span 역역
을 클릭 시 console에 찍히는 화면을 보면 버블링이 보인다. P 영역
에 .self
이벤트를 넣어보자
<template>
<div>
<div id="modifiers">
<div @click.capture="clickDiv">
DIV 영역
<p @click.self="clickP">
P 영역
<span @click.stop="clickSpan"> span 영역 </span>
<a href="https://naver.com" @click.prevent.stop="clickA">a 영역</a>
</p>
</div>
</div>
</div>
</template>
span 영역
을 클릭 했을 때 버블링으로 인한 P 영역
이 보이지 않는다. P 영역
을 눌러보자
이렇게 P 영역
을 눌렀을 때 버블링이 발생하는 걸 볼 수 있다. 이처럼 .self
는 클릭한 요소가 나 자신일 때 이벤트를 실행한다.
버튼을 눌렀을 때 연속적으로 실행이 되는 걸 확인할 수 있는데 이 발생을 한번만 클릭되고 실행이 안되는 걸 볼 수 있다.
<div @scroll.passive="onScroll">....</div>
대체적으로 이렇게 사용한다.
v-on
또는 @
디렉티브에 키 수식어를 제공한다.
.enter
.tab
.delete("Delete"와 "Backspace"키 모두 수신)
.esc
.space
.up
.down
.left
.right
<template>
<div>
<input type="text" @keyup="addTodo" />
<ul>
<li v-for="(todo, index) in todos" :key="index">
{{ todo }}
</li>
</ul>
</div>
</template>
import { reactive } from "vue";
export default {
setup() {
const todos = reactive([]);
const addTodo = evnet => {
todos.push(event.target.value);
};
return {
todos,
addTodo,
};
},
};
이렇게 input에 입력을 했을 때 마다 출력이 되는데 이걸 .enter
를 이용해 enter을 쳤을 때 입력이 가능하게 만들 수 있다.
import { reactive } from "vue";
export default {
setup() {
const todos = reactive([]);
const addTodo = evnet => {
console.log("enter:", event.key);
if (event.key === "Enter") {
todos.push(event.target.value);
event.target.value = "";
event.target.focus;
}
};
return {
todos,
addTodo,
};
},
};
enter의 key
값은 Enter
이기 때문에 if문을 활용해서 Enter
가 입력 되었을 때만 출력하도록 만든다.
이렇게 if문과 key를 통해서 만들 수 있지만 아래와 같이 쉽게 만들 수 있다.
<div>
<input type="text" @keyup.enter="addTodo" />
<ul>
<li v-for="(todo, index) in todos" :key="index">
{{ todo }}
</li>
</ul>
</div>
.enter
을 이용해 만들 수 있다.
.ctrl
.alt
.shift
.meta(Mac에서 meta는 command key, Window에서는 meta는 윈도우키다. 특정 키보드에서 조금 다를 수 있다.)
<template>
<div>
<input type="text" @keyup.ctrl.enter="addTodo" />
<ul>
<li v-for="(todo, index) in todos" :key="index">
{{ todo }}
</li>
</ul>
</div>
</template>
ctrl
+ Enter
키를 같이 눌러야지만 추가가된다.