[Vue]이벤트 처리

chaewon·2024년 4월 23일
0
post-thumbnail

✍🏻이벤트 처리

v-on

  • 이벤트 처리는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(@)디렉티브를 사용함으로써 이벤트를 연결할 수 있다.

디렉티브에서 점(.)하고 붙는 수식어(Modifiers)

  • 우리는 이벤트를 조작할 때 이벤트 내부에서event.preventDefault() 또는 event.stopPropagation() 메서드를 호출할 수 있다. 메소드에서 이러한 메소드의 호출은 어렵지 않지만 메소드 안에서 비즈니스 외에 이러한 코드는 비효율적이다.
    event.preventDefault() -> 기본 기능을 막는 메소드
    event.stopPropagation() -> 이벤트 전파를 막는 메소드
    https://www.youtube.com/watch?v=0jtalJxrxhs 확인이 가능하다.

    .stop = e.stopPropagation()
    .prevent = e.preventDefault()
    .capture = 캡쳐 모드를 사용할 때 이벤트 리스너를 사용 가능합니다.
    .self = 오로지 자기 자신만 호출할 수 있다. 즉 타깃요소가 self일 때 발동된다.
    .once = 해당 이벤트는 한 번만 실행된다.
    .passive = 일반적으로 모바일 장치의 성능을 개선 하기 위해 터치 이벤트 리스너와 함께 사용된다.

.stop

<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,
		};
	},
};

.prevent

<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>

.capture

  • 이벤트의 전파는 캡처링으로 시작해서 버블링으로 마무리되는 플로우다.

    이렇게 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를 먼저 실행하고 그 다음 버블링이 시작된다. 이벤트를 먼저 실행하여야 할 때 활용이 가능하다.

.self

  • 클릭한 요소가 나 자신일 때 이벤트를 실행한다.

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는 클릭한 요소가 나 자신일 때 이벤트를 실행한다.

.once


버튼을 눌렀을 때 연속적으로 실행이 되는 걸 확인할 수 있는데 이 발생을 한번만 클릭되고 실행이 안되는 걸 볼 수 있다.

.passive

  • 일반적으로 모바일 장치의 성능을 개선 하기 위해 터치 이벤트 리스너와 함께 사용된다.
<div @scroll.passive="onScroll">....</div>

대체적으로 이렇게 사용한다.

키 수식어

  • 키보드 이벤트를 수신할 때 종종 특정 키를 확인해야 하는 경우가 있다. 그래서 Vue에서는 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키를 같이 눌러야지만 추가가된다.

profile
의문은 '삶의 수준'을 결정하고, 질문은 '삶 자체'를 바꾼다.

0개의 댓글