cover

사용자에게 웹 사이트를 좀 더 동적인 느낌을 주기 위해선 이벤트 핸들링이 필요합니다. Vue에서는 이런 이벤트 처리를 좀 더 간단하게 할 수 있게 v-on 디렉티브를 지원합니다. 자세히 알아볼까요?


v-on 미리보기

Javascript의 이벤트 핸들링

Javascript에서는 addEventListener로 이벤트를 처리합니다. 만약 button 태그에 대한 이벤트처리를 하고 싶다면 다음과 같이 했습니다.

javascript
      const button = document.querySelector("button");
button.addEventListener("click", function() {
	// 이벤트 처리
});
    

프로젝트가 커지다보면 어디서 button에 대한 이벤트를 처리하는 지 찾기 어려운 문제가 있습니다.

v-on

v-on 디렉티브는 태그의 속성에 처리할 함수를 넣기 때문에 해당 태그의 이벤트 처리가 어떤 함수에서 이뤄지는지 쉽게 알 수 있습니다.

v-on 문법

html
      <태그 v-on:이벤트="함수"></태그>
    
이벤트: click, keyup 등 Javascript에서 사용하는 이벤트명과 동일합니다.
함수: 이벤트가 발생 시 처리할 내용이 들어갑니다.

v-on 약식

@ 기호를 통해 줄여서 사용할 수도 있습니다.

html
      <태그 @이벤트="함수"></태그>
    

예제

간단하게 button이 있고 클릭시 버튼의 값이 1씩 증가하도록 만들어보겠습니다.

html
      <template>
  <div id="app">
    <button @click="counter++">{{ counter }}</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      counter: 0,
    }
  }
};
</script>
    

클릭하면 숫자가 증가하는 것을 볼 수 있습니다.

loading

함수 대신 @click=”counter++”처럼 Javascript 표현식을 넣어도 됩니다. 함수를 사용한다면 다음과 같이 하면 됩니다.

html
      <template>
  <div id="app">
    <button @click="increaseCounter">{{ counter }}</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      counter: 0,
    }
  },
	methods: {
		increaseCounter() {
			this.counter++;
		}
	}
};
</script>
    

v-on 한 이벤트에 여러 함수 사용하기

함수를 여러 개 사용하고 싶다면 comma(,)로 구분해주시면 됩니다.

html
      <태그 @이벤트="함수1($event), 함수2($event)"></태그>
    
javascript
      methods: {
	함수1() {
		// 처리...
	},
	함수2() {
		// 처리...
	},
}
    

함수 입력으로 $event 가 들어가는 것이 보이는데요. 꼭 넣어주셔야 두 개가 같이 실행됩니다.

서로 다른 이벤트라면 몇 개든 넣을 수 있지만, 동일한 이벤트에 대한 처리는 v-on 한 개만 사용할 수 있습니다.

image

v-on event 값

addEventListener를 사용해보셨으면 알겠지만 이벤트를 처리하는 함수는 event값을 받을 수 있는데요.

javascript
      addEventListener("click", function (e) {
	console.log(e);
});
    

눌렀던 키값이나 마우스가 클릭된 위치등을 알 수 있습니다.

image

Vue도 마찬가지로 이 값을 전달받습니다. increaseCounter 에서 아무값도 넣지 않으면 첫 번째 파라미터는 $event 값이 들어갑니다.

javascript
      methods: {
	increaseCounter(e) {
		this.counter++;
		console.log(e)
	}
}
    

v-on 파라미터 전달하기

이벤트 값뿐만 아니라 다른 원하는 값을 전달할 수 있습니다.

html
      <태그 v-on:click="함수(전달값1, 전달값2, ...)"></태그>
    

함수를 만들 때 파라미터를 추가해주면 됩니다.

javascript
      methods: {
	함수(파라미터1, 파라미터2, ...) {
		// 처리처리!
	}
}
    
info
      Q) 그러면 event 값은 어떻게 되죠?
A) 첫 번째 값은 전달받은 값으로 바뀌게 됩니다. event 값이 필요하다면 전달할 때 함수($event, 전달값1, …) 이런식으로 전달해주면 됩니다.
    

v-on 이벤트 수식어

태그마다 이벤트가 발생했을 때 동작하는 특정 기능이 있을 수 있습니다. 예를 들어 form 태그는 submit 이벤트 이후 페이지를 새로고침합니다. Javascript에서는 이러한 동작을 막기 위해 preventDefault라는 함수를 썼었습니다.

javascript
      const form = document.querySelector("form");
form.addEventListener((e) => {
	e.preventDefault(); // 기본 동작 막기
});
    

이렇게 자주 일어나는 것들(캡쳐링, 버블링 등)을 쉽게 처리할 수 있도록 도와주는 것이 바로 수식어입니다.

html
      <p v-on:이벤트.수식어="함수"></p>
    

이 때 함수 없이도 사용 가능합니다.

html
      <p v-on:이벤트.수식어></p>
    

수식어들은 다음과 같이 있습니다.

stop : 이벤트 전파를 막아줍니다. (stopPropagation())
prevent : 태그의 기본 동작을 막아줍니다. (preventDefault())
capture: 하위 태그에서 발생하는 이벤트를 처리하기 전에 여기서 먼저 처리합니다.
self : 자식이 아닌 해당 태그 자체의 이벤트가 발생할 때만 처리합니다.
once : 이벤트를 발생했을 때 한 번만 처리합니다.
passive : passive 기능을 켭니다. passive에 대한 자세한 설명은 MDN을 참조해주세요.

수식어 체이닝

수식어는 체이닝(chaining)이 가능합니다. 예를 들어 클릭에 대한 이벤트를 한 번만 실행하고 기본 동작을 막고싶다면 다음과 같이 하면 됩니다.

html
      <p v-on:click.once.prevent="함수"></p>
    

마우스 수식어

기능에 대한 수식어 뿐만 아니라, 마우스에 대한 수식어도 있습니다.

left : 왼쪽 클릭 시 처리
right : 오른쪽 클릭 시 처리
middle : 휠 클릭 시 처리
html
      <p v-on:click.left="함수"></p>
<p v-on:click.right="함수"></p>
<p v-on:click.middleas="함수"></p>
    

키보드 수식어

마우스가 있다면 키보드도 있겠죠? 키보드는 눌릴 것들이 많기 때문에 그만큼 수식어도 많습니다.

enter
tab
delete (delete, backspace 포함)
esc
space
up
down
left
right
ctrl
alt
shift
meta (맥: command 키, 윈도우: 윈도우키)

그 외에도 영어 키(a ~ z)도 있습니다. 하지만 숫자는 없으니 ASCII 값을 통해 사용해주세요. 그 외에도 F1 키같은 특별키나 숫자를 사용하고 싶다면 keyCode 값을 사용합니다.

html
      <input v-on:keyup.112="submit" />
    

exact 수식어

복사 기능을 만들려고 v-on:keyup.ctrl.c를 추가한다고 할 때 한 가지 문제가 발생합니다. shift+ctrl+c 조합으로 해도 함수가 실행이 되기 때문이죠. ctrl + c 조합으로만 눌렀을 때 동작하게 하려면 exact 수식어를 사용하면 됩니다.

html
      <!-- 아래코드는 Alt 또는 Shift와 함께 눌렀을 때도 실행됩니다.-->
<button @click.ctrl="onClick">A</button>

<!-- 아래코드는 Ctrl키만 눌려져 있을 때 실행됩니다.-->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 아래 코드는 시스템 키가 눌리지 않은 상태인 경우에만 작동합니다.-->
<button @click.exact="onClick">A</button>
    

위 코드 예제는 Vue 공식문서를 참조했습니다.

마무리하며

기존 Javascript의 addEventListener와 달리 태그에 핸들러 함수를 넣으니 어디서 이벤트를 처리하는지 쉽게 알 수 있습니다. 또 태그를 querySelector로 찾을 필요도 없죠. 심지어 이벤트 제거에 대한 걱정도 없습니다. 해당 컴포넌트가 없어지면 이벤트도 같이 자동으로 제거되거든요!