메뉴 바는 만들었지만, 페이지를 이동해도 아무것도 나타나지 않습니다. 이번 글에서는 카테고리를 클릭하면 하단에 글자가 나타나도록 만들어보겠습니다. 이를 위해서는 클릭 이벤트(event)를 처리해야 합니다. 일반적으로 Javascript에서는 addEventListener
나 onXXXX
와 같은 속성을 사용하여 이벤트를 처리합니다. 그러나 우리는 Vue를 사용하고 있기 때문에 다른 방식을 사용해야 합니다. v-on
을 사용하면 Vue의 컴포넌트 데이터를 이용하여 이벤트를 처리할 수 있습니다.
이벤트(event)는 사용자가 웹페이지를 이용하면서 일어나는 모든 상호작용을 말합니다. 페이지가 불러오거나(load
), 마우스로 클릭하거나(click
), 키보드를 누르는 등의 상호작용이 있습니다.
v-on
위에서도 언급했듯이 v-on
은 이벤트를 처리하도록 도와주는 디렉티브입니다.
문법
v-bind
와 비슷한 형태를 가지지만, 속성 대신 이벤트와 이벤트 처리를 다룹니다. v-on:
대신 약식인 @
을 써도 동일하게 동작합니다.
<button v-on:이벤트="이벤트처리"></button>
<button @이벤트="이벤트처리"></button>
이벤트처리에 들어가는 값은 두 가지가 가능합니다.
- 이벤트 처리 내용을 직접 작성합니다. (Inline Handler)
- 컴포넌트의 메소드(함수)를 넣습니다. (Method handler)
<!-- Inline Handler -->
<button @click="counter += 1">더하기</button>
<!-- Method Handler -->
<button v-on:click="subCounter">빼기</button>
콜백 함수
이렇게 이벤트가 발생했을 때 처리를 위해 전달한 함수를 콜백 함수(Callback Function)라 부릅니다. 위 예제에서 subCounter
가 콜백함수입니다.
const subCounter = function (){
counter -= 1;
}
이 콜백함수를 Method handler 형태로 v-on
에 전달하면 event 객체를 전달인자로 받습니다.
const subCounter = function (event){
console.log(event)
}
이를 console.log
로 찍어보면 클릭에 대한 이벤트 객체를 전달해줍니다.

값을 전달하고 싶은 경우
만약 클릭을 하면 특정 값을 함수에 전달하고 싶을 수 있습니다. 그런 경우에는 v-on
에서 해당 함수에 값을 넣어주면 됩니다.
export default {
template: `<button @click="greet('안녕하세요')">버튼</button>`,
setup() {
return {
greet: function (msg) {
console.log(msg);
},
};
},
};
greet 함수는 첫 번째 파라미터 msg
를 받아서 console.log 로 내용을 찍어봅니다. 그리고 v-on
을 통해 greet 함수에 “안녕하세요”를 전달한 것을 볼 수 있습니다.
Inline과 Method 차이
잘 보면 greet('안녕하세요')
는 함수가 아니라 함수를 실행하는 문장입니다. 따라서 이는 Inline Handler입니다. Inline Handler는 단순히 JavaScript 내용을 실행하는 것이기 때문에 이벤트를 전달받지 않습니다. 그래서 이벤트 값을 전달하려면 $event
를 추가해주시면 됩니다.
export default {
template: `<button @click="greet($event, '안녕하세요')">버튼</button>`,
setup() {
return {
greet: function (event, msg) {
console.log(event, msg);
},
};
},
};

console.log에 다음과 같이 나타나네요!
Q] $event는 무엇인가요? A] Vue에서$event
템플릿에서 사용되는 특수 변수입니다. 이벤트 외에도 속성을 위한$attrs
, 컴포넌트간에 통신을 위한$props
,$emit
등이 있습니다. 그 외에도 많이 있지만 다루기엔 주제에서 많이 벗어나기 때문에 공식 홈페이지를 참조해주세요!
이벤트 수식어
Javascript에서 이벤트를 다룰 때 event.preventDefault()
함수나 event.stopPropagation()
을 사용하는 경우가 있습니다. 이 함수들은 해당 태그가 가진 고유의 이벤트 처리 기능을 제거하거나 이벤트가 상위 태그로 전달되는 것을 막습니다. 이러한 기능은 콜백 함수에서 실행할 수 있지만, v-on
은 이벤트 수식어(event modifiers)를 통해 더 간편하게 실행할 수 있습니다.
<tag @이벤트.수식어="이벤트 처리"></tag>
이런 수식어는 몇 가지가 있습니다. 자주 사용하는 예시를 보이자면…(공식 홈페이지를 참조했습니다)
<!-- 클릭 이벤트가 상위 태그로 전달되는 것을 막아줍니다 -->
<a @click.stop="doThis"></a>
<!-- form 태그의 고유한 submit 이벤트 처리 기능이 동작하는 것을 막습니다 -->
<form @submit.prevent="onSubmit"></form>
<!-- modifier를 여러 개를 동시에 사용할 수 있습니다. (체이닝) -->
<a @click.stop.prevent="doThat"></a>
<!-- 굳이 처리할 내용이 없는 경우 modifier만 사용해도 됩니다. -->
<form @submit.prevent></form>
<!-- 만약 자식 태그가 있는 경우 자식이 클릭 되는 경우는 처리하지 않고 -->
<!-- 이 태그만 해당되는 곳에 이벤트 발생하면 처리합니다. -->
<div @click.self="doThat">...</div>
그 외에도 키 동작을 위한 Modifiers들도 있습니다.
<!-- enter 키를 떼어냈을 때 실행 -->
<input @keyup.enter="submit" />
<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
그 외에도 다양한 것들이 있으니 더 자세한 내용이 필요하신 분은 공식 홈페이지 또는 제 블로그를 참조해주세요!
선택한 카테고리 글 목록 보이기
이제 값을 선택한 카테고리 글 목록이 나타나도록 만들어보겠습니다. 그 전에 우선 클릭이 잘 실행되었는지 알 수 있게 함수(clickCategory
)에 console.log를 사용해보겠습니다.
// ...
setup() {
const categories = ["HTML", "CSS", "Javascript"];
const clickCategory = function (category) {
console.log(category);
};
return {
categories,
clickCategory,
};
},
}
그리고 v-on
을 이용해서 clickCategory 값에 category 값을 전달하겠습니다.
// ...
template: `
<nav class="menu">
<a
...
@click.prevent="clickCategory(c)"
>
{{ c }}
</a>
</nav>
`,
// ...
이 때 중요한 것은 prevent
수식어를 추가한 것입니다. 왜냐하면 a 태그를 클릭하는 순간 href
속성이 지정한 URL로 이동할 것이기 때문에, 이 기능을 막아야 합니다. 이렇게해서 실행을 해보겠습니다.

잘 되는 것 같네요! 전체 코드입니다!
export default {
template: `
<nav class="menu">
<a
v-for="c of categories"
:key="c"
:href="'/' + c.toLowerCase()"
class="category"
@click.prevent="clickCategory(c)"
> {{ c }}</a>
</nav>
`,
setup() {
const categories = ["HTML", "CSS", "Javascript"];
const clickCategory = function (category) {
console.log(category);
};
return {
categories,
clickCategory,
};
},
};
글 목록 만들기
이제 카테고리가 콜백 함수로 잘 전달되는 것을 확인했습니다. 선택된 카테고리 값을 저장하고, 이 값을 글 목록 제목으로 나타내 보겠습니다.
먼저, template
에서 메뉴 바 아래에 간단한 글 목록용 태그를 만듭니다. 그리고 선택된 카테고리 값을 selectedCategory
변수에 저장합니다.
template: `
<nav class="menu">
...
</nav>
<main class="post-list">
<h2>카테고리: {{ selectedCategory }}</h2>
</main>
`,
그리고 이제 클릭 시 선택된 카테고리 값을 selectedCategory
변수에 저장하도록 수정해보겠습니다.
setup() {
const categories = ["HTML", "CSS", "Javascript"];
let selectedCategory = "HTML";
const clickCategory = function (category) {
selectedCategory = category;
};
return {
categories,
selectedCategory,
clickCategory,
};
},
이제 실행해보면 이상하게도 아무런 변화가 없습니다.

컴포넌트 데이터가 변경되었지만 DOM은 변경되지 않은 경우, Vue는 이를 감지하지 못합니다. 이러한 데이터 바인딩은 초기 렌더링 시에만 적용되며, 이후 데이터가 변경되면 Vue는 이에 대해 반응하지 않습니다.
Vue는 컴포넌트 데이터의 변화를 감지하고 DOM을 다시 그리기 위해 데이터를 반응형 상태로 변경해야 합니다. 이 방법에 대해서는 다음 글에서 다루겠습니다.