4. 이벤트처리

4. 이벤트 처리

다양한 이벤트처리를 Vue 기반으로 작성

이벤트 참고

이벤트 참고 문헌, 모질라, w3스쿨스

4.1 인라인 이벤트처리

인라인 레벨에서 이벤트처리 하는 방법을 다룸

  • v-on 디렉티브

    • Click 이벤트 처리

      v-on:click 또는 @click

      <div id="example" class="container layout1">
      <p>
        <input type="text" v-model="amount" class="form-control">
      </p>
      <p>
        <button id="deposit" v-on:click="balance += parseInt(amount)" class="btn btn-primary">예금</button>
        <button id="withdraw" @click="balance -= parseInt(amount)" class="btn btn-primary">인출</button>
      </p>
      <h3>계좌 잔고 : {{balance}}</h3>
      </div>

4.2 이벤트 핸들러 메서드

인라인에서 디렉티브에 바로 코딩하는 것이 아닌, 메서드를 미리 구현하여 참조 위 예제에서 v-on디렉티브 부분deposit와 withdraw메서드에 참조하여 상세처리를 함

  • HTML

    <button id="deposit2" @click="deposit" class="btn btn-primary">예금</button>  
    <button id="withdraw2" @click="withdraw" class="btn btn-primary">인출</button>
  • JS

    let vm2 = new Vue({
      el: '#example2',
      data: {
        amount: 0,
        balance: 0
      },
      methods: {
        deposit: function (e) {
          let amt = parseInt(this.amount);
          if (amt <= 0) {
            alert('0 보다 큰 값을 예금해야 합니다');
          } else {
            this.balance += amt;
          }
        },
        withdraw: function (e) {
          let amt = parseInt(this.amount);
          if (amt <= 0) {
            alert('0 보다 큰 값을 인출 할 수 없습니다.');
          } else if (amt > this.balance) {
            alert('잔고보다 많은 금액을 인출 할 수 없습니다.');
          } else {
            this.balance -= amt;
          }
        }
      }
    });

4.3 이벤트 객체

function(e){...}에서 첫번째 파라미터는 이벤트 객체 W3C의 표준 DOM Event 모델을 그대로 따르며, 추가적인 속성을 다룬다. 따라서 순수JS에서 사용하는 방법 그대로 이용 가능 딱히 설명은 없고 정리된 글로, 책에서 정리한 표를 참고. 따로 사용예는 없다

자주 쓰는 target, currentTarget, defaultPrevented.. 등등 속성 정리되어 있음. 한번쭉 읽어보기

4.4 기본이벤트

기본이벤트란 태그특징에 의해 이벤트가 내장되어 있는 것. ex) <a>href속성을 통한 클릭이벤트 ex) <form>의 submit 버튼 -> action ex) <input type='text'>키이벤트

편하긴 하지만 때로는 이런 기본이벤트가 걸림돌이 되는 경우가 있어서 이를 중지 시킬수 있는 방법!!

  • preventDefault함수 대상 이벤트의 실행을 중단시켜줍니다.

    • HTML

      <div id="example3" v-on:contextmenu="ctxStop">
      <a href="https://facebook.com" @click="confirmFB">페이스북</a>
      </div>
    • JS

      여기에서 ctxStop -> 해당div에 걸리분부분 context메뉴 관련 이벤트 중단(마우스 우클릭 같은..)

      let vm3 = new Vue({
        el: '#example3',
        methods: {
          ctxStop: function (e) {
            console.log("ctx");
            e.preventDefault();
          },
          confirmFB: function (e) {
            console.log("faceFB");
            if (!confirm('페이스북으로 이동할까요?')) {
              e.preventDefault(); // e는 a태그, 취소 버튼 클릭시 : a태그의 이동을 중지시킴.
            }
          }
        }
      });
  • 이벤트 수식어 v-on:contextmenu.prevent 처럼 명시하면 preventDefault가 적용됨. 매번 코딩하는 번거로움을 덜어주는 방식

<div id="example3" v-on:contextmenu.prevent>
  <a href="https://facebook.com" @click="confirmFB">페이스북</a>
</div>

4.5 이벤트 전파와 버블링

HTML문서의 이벤트 처리는 3단계로 구성.

  • 1단계

    문서내의 요소 이벤트 발생, HTML 문서 밖에서부터 이벤트를 발생시킨 HTML요소까지 포착, 포착단계(capturing)

  • 2단계

    이벤트를 발생시킨 요소에 다다르면, 이벤트에 연결된 함수를 직접호출 시킴, 이벤트 발생단계(raising)

  • 3단계 이벤트가 발생한 요소로부터 상위요소로 거슬러 올라가면서 동일이벤트 호출, 버블링단계(bubbling

  • 예시 inner(노랑색)를 클릭시 -> outer(아쿠아색)도 실행 (버블링) - 문제요소 inner 클릭시 -> outer부분에서 cuurentTarget은 outer, target은 inner

    확인

    inner click

    outer click

    eventPhase

    2(AT_Target)

    3(BUBBLING)

    cuurent target

    inner

    outer

    target

    inner

    inner

  • HTML

    <div id="example4">
    <div id="outer" @click="outerClick">
      <div id="inner" @click="innerClick"></div>
    </div>
    </div>
  • JS

    let vm4 = new Vue({
      el: '#example4',
      methods: {
        outerClick: function (e) {
          console.log('### OUTER CLICK');
          console.log('Event Phase : ', e.eventPhase);
          console.log('Current Target : ', e.currentTarget);
          console.log('Target : ', e.target);
        },
        innerClick: function (e) {
          console.log('### INNER CLICK');
          console.log('Event Phase : ', e.eventPhase);
          console.log('Current Target : ', e.currentTarget);
          console.log('Target : ', e.target);
        }
      }
    });
  • 해결 방법

    • 이벤트 객체의 stopPropagation() 호출

      let vm4 = new Vue({
        el: '#example4',
        methods: {
          outerClick: function (e) {
            console.log('### OUTER CLICK');
            console.log('Event Phase : ', e.eventPhase);
            console.log('Current Target : ', e.currentTarget);
            console.log('Target : ', e.target);
            e.stopPropagation();
          },
          innerClick: function (e) {
            console.log('### INNER CLICK');
            console.log('Event Phase : ', e.eventPhase);
            console.log('Current Target : ', e.currentTarget);
            console.log('Target : ', e.target);
            e.stopPropagation();
          }
        }
      });
    • 이벤트 수식어 .stop을 추가하면 stopPropagation이 자동 추가됨

      <div id="example4">
        <div id="outer" @click.stop="outerClick">
          <div id="inner" @click.stop="innerClick"></div>
        </div>
      </div>
      • .stop : 이벤트 버블링 중단

      • .capture : 캡쳐링단계(1단계)에서만 이벤트 발생

      • .self : 라이징단계(2단계)에서만 이벤트 발생

      • 체인방식 가능 : @click.capture.stop 처럼 사용 가능

        <div id="example4">
          <div id="outer" @click.capture.stop="outerClick">
            <div id="inner" @click.stop="innerClick"></div>
          </div>
        </div>

        좀 다르게 동작, inner 클릭시 포착단계에서 outer만 실행되고 전파를 중지하게 되므로 inner 실행이 안됨

4.6 이벤트 수식어

활용시 단순 코딩을 줄일 수 있다. 앞에서 살펴본 .prevent, .stop, .capture, .self 외 살펴보기

  • once 수식어

    이벤트를 한번만 발생

<button id="create" @click.once="specialEvent" class="btn btn-primary">계좌개설 10000원 이벤트</button>
  • 키코드 수식어

    키보드 클릭시 키에 대한 고유 키코드 값을 가질때만 이벤트 발생 ex) v-on:keyup.13="함수", 13(엔터키)

    • HTML

      <div id="example6" v-cloak>
      <p>
        이름 : <input type="text" v-model="name" v-on:keyup="search" placeholder="두자 이상 입력">
        <!--    이름 : <input type="text" v-model="name" v-on:keyup.13="search" placeholder="두자 이상 입력">-->
      </p>
      <table id="list">
        <thead>
        <tr>
          <th>번호</th>
          <th>이름</th>
          <th>전화번호</th>
          <th>주소</th>
        </tr>
        </thead>
        <tbody id="contracts">
        <tr v-for="contact in contactlist">
          <td>{{contact.no}}</td>
          <td>{{contact.name}}</td>
          <td>{{contact.tel}}</td>
          <td>{{contact.address}}</td>
        </tr>
        </tbody>
      </table>
      <div v-show="isProcessing === true">조회중</div>
      </div>
    • JS

      let vm6 = new Vue({
        el: '#example6',
        data: {
          name: '',
          isProcessing: false,
          contactlist: []
        },
        methods: {
          search: function (e) {
            if (e.keyCode === 13) {     // 이부분 수식어로 대체가능
              let val = e.target.value;
              if (val.length >= 2) {
                this.fetchContacts();
              } else {
                this.contactlist = [];
              }
            }
          },
          fetchContacts: function () {
            this.contactlist = [];
            this.isProcessing = true;
            var url = "http://sample.bmaster.kro.kr/contacts_long/search/" + this.name;
            var vm = this;
            fetch(url)
                .then(function (res) {
                  return res.json();
                })
                .then(function (json) {
                  vm.contactlist = json;
                  vm.isProcessing = false;
                })
                .catch(function (err) {
                  console.log('parsing failed', err);
                  vm.contactlist = [];
                  vm.isProcessing = false;
                });
          }
        }
      });

    키코드 값을 일일이 기억할 수 없으므로, 몇가지에 대해 Vue.js에서 수식어로 별칭을 제공함

    • ex) .enter, .tab, .delete, .esc, .space 등등.. 책 참고

    • 여러개 결합사용 가능 : @keyup.ctrl.67='copy', ctrl+c 키 입력시

      이름 : <input type="text" v-model="name" @keyup.ctrl.67="copy" placeholder="테스트copy">
  • 마우스 버튼 수식어

    .left(왼), .right(오), .middle(휠)

    • HTML

      ```html

      Left Click : 왼쪽으로

      Right Click : 오른쪽으로

      </div>

      <img src="http://sample.bmaster.kro.kr/img/foot.jpg"

      v-bind:style="{position:'absolute', left:pos.left+'px', top:pos.top+'px'}">

    </div>

    - JS
    ```javascript
    let vm7 = new Vue({
      el: '#example7',
      data: {
        pos:{left:100, top: 100}
      },
      methods: {
        ctxStop: function (e) {
        },
        leftMouse: function (e) {
          if (this.pos.left > 30) {
            this.pos.left -= 30;
            console.log("Move Left!!");
          }
        },
        rightMouse: function (e) {
          this.pos.left += 30;
          console.log("Move Right");
        }
      }
    });

Last updated