Vue 3.0/02.Essentials

[vue 3] 08.v-on

  • -

이번 포스트에서는 Vue에서 이벤트 처리에 사용되는 v-on 디렉티브에 대해 살펴보자.

 

Vue의 이벤트 처리 방식

 

v-on

Vue에서 이벤트를 처리하기 위해서는 v-on directive를 사용한는데 통상 v-on을 @로 대체해서 축약형으로 사용한다.

v-on:이벤트명=”handler"

@이벤트명="handler"

즉 click이벤트를 처리하기 위해서는 v-on:click="handler" 또는 @click="handler"형태로 사용한다.

 

handler 등록 방식

이벤트 발생 시 동작할 handler를 등록하는 방식으로는 inline handler 방식과 method handler 방식 2가지가 제공된다.

inline handler 방식은 한 줄의 간단한 실행문을 처리하거나 미리 작성된 함수를 직접 실행하는 경우 사용된다. 반면 method handler 방식은 미리 만들어 놓은 함수를 콜백으로 등록해서 사용하는 경우이다.

비고 inline handler 방식 method handler 방식
동작 특성 한 줄의 간단한 실행문을 처리하거나 미리 작성된 함수를 직접 실행하는 형태 미리 만들어 놓은 함수를 콜백으로 등록하는 형태
파라미터 전달 함수 실행 시 파라미터 전달 가능 호출하지 않으므로 전달 불가
이벤트 객체 함수 실행 시 명시적으로 전달 필요 콜백 호출 시 내부적으로 이벤트 객체 전달
<!-- 한줄의 간단한 실행문을 사용하는 경우 -->
<button v-on:click="info.balance+=info.amount">입금</button>

<!-- 미리 작성된 함수를 직접 실행하는 경우 -->
<button v-on:click="deposite()">입금</button>

<!-- 미리 작성된 함수를 콜백으로 등록하는 형태 -->
<button v-on:click="deposite">입금</button>

 

활용 예

잔고에 대해 입금, 출금하는 경우를 각각 inline handler 방식과 method handler 방식을 이용해서 처리해보자.

먼저 script 영역을 살펴보면 balance와 amount 속성을 갖는 info 객체와 출금을 위한 withdraw, 입금을 위한 deposite 함수가 선언되어있다.

const { createApp, reactive } = Vue;

createApp({
  setup() {
    const info = reactive({ balance: 100, amount: 10 });
    const withdraw = () => {
      if (info.balance >= info.amount) {
        info.balance -= info.amount;
      } else {
        alert("잔액 부족");
      }
    };
    const deposite = () => {
      info.balance += info.amount;
    };

    return {info, withdraw, deposite, };
  },
}).mount("#app");

 

다음은 template 부분을 살펴보자. 4개의 버튼에서 click 이벤트를 처리하고 있다. 이 중 입금을 처리하는 부분을 살펴보자.

<div id="app">
    현재 잔고: <span>{{info.balance}}</span>
    <hr />
    <label>거래 금액: </label>
    <input type="number" v-model.number="info.amount" />
    <button v-on:click="info.balance+=info.amount">입금</button>
    <button v-on:click="deposite()">입금</button>
    <button v-on:click="deposite">입금</button>

    <button @click="withdraw">출금</button>
</div>

처음 버튼은 inline 방식으로 실행할 문장을 직접 작성한 예이다. 두 번째 버튼도 사실 미리 작성된 javascript 함수를 실행하는 형태이며 ()에 직접 전달할 파라미터를 넘겨줄 수 있다. 3번째 입금 버튼은 콜백 함수를 등록한 형태로 파라미터를 전달할 수는 없다.

 

이벤트 객체와 수식어

 

이벤트 객체의 활용

이벤트 객체는 이벤트 소스를 포함한 이벤트에 대한 상세한 정보를 얻기 위해서 사용된다. vue에서는 v-on으로 호출되는 함수에 event라는 변수로 event 객체가 묵시적으로 제공된다. 

만약 event라는 이름으로 사용자 정의 변수를 꼭 써야겠다면 호출 방식에 따라 event 객체를 다른 변수로 할당할 수 있다. method handler 방식을 이용해서 이벤트 콜백을 등록하는 경우는 콜백이 호출되면서 언제나 첫 번째 파라미터로 이벤트 객체가 전달된다. 하지만 inline handler 방식은 함수 호출 시점에 명시적으로 이벤트 객체를 전달해주어야 하는데 이때 $event 키워드가 사용된다.

다음은 이벤트 헨들러에서 이벤트 객체를 활용하는 코드이다.  useEventObject 함수는 첫 번째 파라미터가 이벤트 객체이고 두 번째는 함수 동작에 필요한 파라미터 이다.

<script>
  const { createApp } = Vue;

  createApp({
    setup() {
      const useEventObject = (e, param) => {
        console.log(`html: ${e.target.innerHTML}, param: ${param}`);
      };
      return { useEventObject };
    },
  }).mount("#app");
</script>

 

template에서 위 헨들러가 호출되면서 event 객체와 파라미터를 넘기는 방식을 살펴보자.

<div id="app">
    <button @click="useEventObject">method handler</button>
    <button @click="useEventObject($event, 'hello')">inline handler(normal)</button>
    <button @click="(event) => useEventObject(event, 'Hi')">inline handler(arrow)</button>
</div>

처음 버튼은 method handler를 이용하는 방법이다. 이 경우 이벤트 객체를 넘기기 위한 노력은 필요 없지만 파라미터도 넘길 수가 없다.  파라미터를 넘기기 위해서는 두 번째 버튼처럼 inline 방식을 사용해야 하는데 이 경우 $event 키워드를 이용해서 명시적으로 이벤트 객체를 넘겨줘야 한다. 

arrow 함수를 등록 시키는 3번째 버튼은 사실 1번 처럼 콜백의 등록이고 호출 시 첫 번째 파라미터로 event 객체가 전달되므로 내부에서 전달된 event 객체와 parameter를 이용해서 다시 handler를 호출한다.

 

이벤트 객체의 주요 속성

이벤트 객체를 사용하는 경우는 이벤트가 발생한 DOM 객체인 이벤트 소스를 파악하거나 여러가지 이벤트에 대한 상세 정보를 파악해서 프로그램에 사용하기 위함이다. 다음은 이벤트 객체가 가지는 다양한 속성과 함수들이다.

구분 속성명 설명
공통속성 currentTarget 이벤트 소스(이벤트가 발생한 DOM 객체)
path 배열로 target 부터 window까지 조상을 찾아가는 경로
공통함수 preventDefault 기본 이벤트 동작을 중지시킴
stopPropagation 이벤트 전파를 막음
키보드
이벤트
altKey, shiftKey, ctrlKey 각각 alt, shift, ctrl 키가 눌렸는지 여부(true/false)
keyCode 이벤트를 발생시킨 키보드의 고유 키 코드(enter: 13 )
charCode keyPress 이벤트에서 눌린 unicode 캐릭터 코드
마우스
이벤트
altKey, shiftKey, ctrlKey 키보드 이벤트 참조
clientX, clientY viewport 영역에서 이벤트가 발생한 좌표로 스크롤된 길이에 영향을 받지 않음
pageX, pageY document 영역에서 이벤트가 발생한 좌표로 스크롤된 길이에 영향을 받음
screenX, screenY screen 영역에서 이벤트가 발생한 좌표

얼핏 보면( 활용도 면에서도) 매우 중요한 내용들이지만 신기하게도 위 내용을 사용할 일은 거의 없다. 왜냐하면 Vue에서는 이벤트 수식어를 통해서 위의 내용들을 손쉽게 사용할 수 있는 방법을 제시하기 때문이다.

 

이벤트 수식어(event modifier)

이벤트 수식어는 directive 사용 시 전달인자 뒤에 .을 이용해서 연결해준다.

v-on:event_name.event_modifier=handler

@event_name.event_modifier=handler

다음은 이벤트의 공통 기능/속성에 대한 이벤트 수식어들이다. 여러가지가 있기는 하지만 가장 대표적으로 사용되는 수식어는 prevent로 preventDefault()를 대체한다.

구분 수식어 명 설명
공통 prevent 이벤트의 기본 동작( <form> submit 전송, <a> 클릭 페이지 전환 등) 방지
preventDefault() 대체
stop 하나의 이벤트가 여러 요소에 걸쳐 발생할 때 전파 중단
stopPropagation() 대체
capture 캡쳐링 상태에서 이벤트 처리
self event.currentTarget이 자신인 경우만 처리
once 한번만 이벤트를 발생시키고 이후는 동작하지 않음

 

다음 예는 <form>의 <input>에서 login을 위해 id를 입력받는 과정에서 4글자 이상인 경우만 처리하기 위해서 prevent를 사용하는 경우 이다. 이 경우는 글자가 4글자 미만인 경우는 submit 이벤트가 발생하지 않으며 4글자 이상인 경우만 명시적으로 submit() 동작이 발생한다.

<div id="app">
    <form action="#" @submit.prevent="login">
        <label>ID:</label><input type="text" placeholder="ID는 4글자 이상입니다." v-model="id" />
        <input type="submit" />
    </form>
</div>

<script>
  const { createApp, ref } = Vue;

  createApp({
    setup() {
      const id = ref("");
      const login = (e) => {
        if (id.value.length < 4) {
          alert("ID는 4글자 이상으로 입력하세요.");
        } else {
          e.target.submit();
        }
      };
      return { id, login, };
    },
  }).mount("#app");
</script>

 

다양한 이벤트 수식어

사실 vue를 통해서는 <form>의 submit 이벤트를 처리할 일이 거의 없다. 왜냐하면 거의 모든 처리가 ajax를 통하기 때문이다. 대신 key event나 mouse 이벤트에서 이벤트의 상세 정보를 알기 위한 동작이 훨씬 빈번하다.

구분 수식어 명 설명
Key Modifier 숫자 입력되는 키에 대한 키 코드 입력 값(대표적인 키들은 상수로 등록됨) 제한
enter, tab, delete, esc, space, up, down, left, right, ctrl, alt, shift, meta


조합 키의 경우 수식어 연결 사용 @keyup.ctrl.67="event_name"
Mouse Modifier left, right, middle 각각 마우스의 어떤 버튼이 클릭 됐는지 로 제한

다음의 코드를 읽고 어떤 식으로 동작할 것인지 생각해보자.

<div id="app">
<div
  @contextmenu.prevent=""
  @mouseup.right="moveRight(10)"
  @mouseup.left="moveRight(-10)"
  style="border: 1px solid blue; width: 200px; height: 200px"
>
  <span :style="'position: absolute; top:'+pos.top+'px; left:'+pos.left+'px'">@</span>
</div>
</div>

 

'Vue 3.0 > 02.Essentials' 카테고리의 다른 글

[vue 3] 10.computed  (0) 2022.07.02
[vue 3] 09.DOM 요소에 직접 접근  (0) 2022.06.28
[vue 3] 07.v-model  (0) 2022.06.26
[vue 3] 06.v-for  (0) 2022.06.25
[vue 3] 05.조건문을 위한 v-if, v-show  (0) 2022.06.24
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.