Today I Learned

이벤트 처리 본문

Vue.js

이벤트 처리

하이라이터 2019. 5. 1. 23:26
728x90

인라인 이벤트 처리

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>04-01</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <style>
        .layout1 {
            margin: 30px 30px 30px 30px;
        }
    </style>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
</head>

<body>
    <div id="example" class="container layout1">
        <p><input type="text" v-model="amount" class="form-control" /></p>
        <p>
            <button id="deposit" @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>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#example",
            data: {
                amount: 0,
                balance: 0,
            }
        })
    </script>
</body>

</html>

v-on 디렉티브를 이용한 이벤트 처리

v-model로 amount 데이터 속성을 양방향 바인딩

v-on:click 디렉티브를 이용해 클릭 이벤트 처리를 수행

v-on 디렉티브는 @로 줄여쓸 수 있다. ( 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="deposit($event)" class="btn btn-primary">예금</button>
            <button id="withdraw" v-on:click="withdraw" class="btn btn-primary">인출</button>
        </p>
        <h3>계좌 잔고 : {{balance}}</h3>
    </div>

    <script type="text/javascript">
        var vm = new Vue({
            el: "#example",
            data: {
                amount: 0,
                balance: 0,
            },
            methods: {
                deposit: function(e) {
                    var amt = parseInt(this.amount);
                    if (amt <= 0) {
                        alert("0보다 큰 값을 예금해야 합니다");
                    } else {
                        this.balance += amt;
                    }
                },
                withdraw: function(e) {
                    var amt = parseInt(this.amount);
                    if (amt <= 0) {
                        alert("0보다 큰 값을 인출할 수 있습니다");
                    } else if (amt > this.balance) {
                        alert("잔고보다 많은 금액을 인출할 수 없습니다");
                    } else {
                        this.balance -= amt;
                    }
                }
            }
        })
    </script>

Vue 인스턴스에 deposit, withdraw 메서드를 작성

메서드에 금액과 계좌 잔고에 따른 유효성 검사 기능 추가

 


이벤트 객체

이벤트를 처리하는 메서드는 첫 번째 파라미터로 이벤트 객체를 전달받음

Vue.js의 이벤트 객체는 W3C 표준 HTML, DOM Event 모델을 그대로 따르면서 추가적인 속성을 제공

→기존 자바스크립트의 이벤트 객체 정보를 거의 대부분 이용가능

 

  • 이벤트 객체의 주요 공통 속성
속성명 설명
target 이벤트가 발생한 HTML 요소를 리턴함
currentTarget 이벤트리스너가 이벤트를 발생시키는 HTML 요소를 리턴함
path 배열값, 이벤트 발생 HTML 요소로부터 document, window 객체로까지 거슬러 올라가는 경로를 나타냄
bubbles 현재의 이벤트가 버블링을 일으키는 이벤트인지 여부를 리턴함
defaultPrevented 기본 이벤트가 방지되었는지 여부를 나타냄
eventPhase

이벤트 흐름의 단계를 나타냄

1 : 포착(CAPTURING_PHASE)

2 : 이벤트 발생(AT_TARGET)

3 : 버블링(BUBBLING_PHASE)

srcElement IE에서 사용되던 속성으로 target과 동일한 속성

 

  • 키보드 이벤트 관련 속성
속성명 설명
altKey ALT 키가 눌려졌는지 여부를 나타냄(true/false)
shiftKey SHIFT 키가 눌려졌는지 여부를 나타냄(true/false)
ctrlKey CTRL 키가 눌려졌는지 여부를 나타냄(true/false)
metaKey 메타키가 눌려졌는지 여부를 나타냄. 윈도우에서는 Window Key, macOS 에서는 Command Key
Key 이벤트에 의해 나타나는 키의 값을 리턴함. 대소문자 구분함
code

이벤트를 발생시킨 키의 코드값을 리턴함

ex) A 키를 눌렀을때 "KeyA"를 리턴
ex) SHIFT 키를 눌렀을때 "Shift"를 리턴

KeyCode

이벤트를 발생시킨 키보드의 고유 키코드

ex) a, A는 65를 리턴함 (대소문자 구분하지 않음)

charCode keypress 이벤트가 발생될 때 Unicode 캐릭터 코드를 리턴함
location 디바이스에서의 키 위치값, 일반 키보드는 이 값이 모두 0이므로 이용할 수 없음

 

  • 마우스 이벤트 관련 속성
속성명 설명
altKey, shiftKey
ctrlKey, metaKey
키보드 이벤트 관련 속성 참조
button

이벤트를 발생시킨 마우스 버튼

0 : 마우스 왼쪽 버튼

1 : 마우스 휠

2 : 마우스 오른쪽 버튼

buttons

마우스 이벤트가 발생한 후에 눌려져있는 마우스 버튼의 값을 리턴함. 아래 값의 조합으로 이루어짐

1 : 마우스 왼쪽 버튼

2 : 마우스 오른쪽 버튼

4 : 마우스 휠

8 : 4번째 마우스 버튼

16 : 5번째 마우스 버튼

ex) 마우스 오른쪽 버튼, 휠을 누르고 있는 상태에서 왼쪽 버튼을 클릭할 경우 이 값은 6을 리턴함

clientX, clientY 마우스 이벤트가 일어났을 때의 뷰포트(ViewPort) 영역상의 좌표, 이 좌표는 스크롤바를 내리더라도 좌표값에 영향을 받지 않음
layerX, layerY 마우스 이벤트가 발생한 HTML 요소 영역상에서의 좌표 (IE 이외의 브라우저 사용)
offsetX, offsetY 마우스 이벤트가 발생한 HTML 요소 영역상에서의 좌표 (IE 브라우저 사용)
pageX, pageY 마우스 이벤트가 일어났을 때의 HTML 문서(Document) 영역상의 좌표
screenX, screenY 마우스 이벤트가 일어났을 때의 모니터 화면(Screen) 영역상의 좌표

 

  • 이벤트 객체의 주요 메서드
속성명 설명
preventDefault() 기본 이벤트의 자동 실행을 중지시킴
stopPropagation() 이벤트의 전파를 막음

 


기본이벤트

HTML 문서나 요소에 어떤 기능을 실행하도록 이미 정의되어 있는 이벤트

 

대표적인 기본 이벤트

  • <a> 요소를 클릭했을 때 href 특성의 경로로 페이지를 이동시킴
  • 브라우저 화면을 마우스 오른쪽 클릭했을 때 내장 컨텍스트 메뉴(ContextMenu)가 나타남
  • <form> 요소 내부의 submit 버튼을 클릭했을 때 action 특성에 지정된 경로, method 특성에 지정된 방식으로 전송함
  • <input type="text" ... /> 요소에 키보드를 누르면 입력한 문자가 텍스트 박스에 나타남

기본이벤트 실행을 중지시키는 방법

    <div id="example" v-on:contextmenu.prevent="ctxStop">
        <a href="https://facebook.com" @click="confirmFB">페이스북</a>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#example",
            methods: {
                ctxStop: function(e) {

                },
                confirmFB: function(e) {
                    if (!confirm("페이스북으로 이동할까요?")) {
                        e.preventDefault();
                    }
                }
            }
        })
    </script>

confirm 창에서 취소 버튼을 클릭하면 preventDefault() 메서드가 호출되어 <a> 요소의 기본이벤트인 URL 이동을 막음

이벤트 수식어(Event Modifier)를 통해서도 기본이벤트 제어 가능 → contextmenu.prevent로 컨텍스트메뉴 호출 막음

* 이벤트수식어 : 다양한 이벤트와 관련된 문제를 쉽게 해결하기 위해 제공

 


이벤트 전파와 버블링

HTML 문서의 이벤트 처리 3단계

  • 1단계 : 이벤트 포착 단계 (CAPTURING_PHASE)
    문서 내의 요소에서 이벤트가 발생했을 때 HTML 문서의 밖에서부터 이벤트를 발생시킨 HTML 요소까지 포착해 들어가는 단계
  • 2단계 :이벤트 발생 단계 (RASING_PHASE)
    이벤트를 발생시킨 요소에 다다르면 요소의 이벤트에 연결된 함수를 직접 호출시키는 단계
  • 3단계 : 버블링 단계 (BUBBLING_PHASE)
    이벤트가 발생한 요소로부터 상위 요소로 거슬러올라가면서 동일한 이벤트를 호출시키는 단계

이벤트 전파

    <div id="example">
        <div id="outer" @click="outerClick">
            <div id="inner" @click="innerClick"></div>
        </div>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#example",
            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();
                }
            }
        })
    </script>

 

#inner 요소를 클릭하면 #outer의 click 이벤트까지 실행된다.

일반적으로 이벤트 버블링은 막아야 할 작업 (#inner를 클릭했을 때 상위 요소로의 이벤트 전파는 막아야함)

→ 이를 위해 이벤트 객체의 stopPropagation() 메서드를 호출

코드에서 주석처리한 e.stopPropagation()을 사용하거나 @click 대신 @click.stop 이벤트 수식어로 대체 가능

 

이벤트 전파와 관련된 이벤트  수식어

  • .stop : 이벤트 전파를 중단
  • .capture : CAPTURING_PHASE 단계에서만 이벤트가 발생
  • .self : RAISING_PHASE 단계에서만 이벤트가 발생

이벤트 객체의 주요 속성값 비교

  #inner click #outer click
eventPhase 2 (AT_TARGET) 3 (BUBBLING)
current target #inner #outer
target #inner #inner (이벤트가 일어난 원본 요소)

 


이벤트 수식어

once 수식어

한번만 이벤트를 발생시킴

    <div id="example" class="container layout1">
        <p><input type="text" v-model="amount" class="form-control" /></p>
        <p>
            <button id="create" v-on:click.once="specialEvent" class="btn btn-primary">
            	계좌 개설 10000원 이벤트</button>
            <button id="deposit" v-on:click="deposit($event)" class="btn btn-primary">예금</button>
            <button id="withdraw" v-on:click="withdraw" class="btn btn-primary">인출</button>
        </p>
        <h3>계좌 잔고 : {{balance}}</h3>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#example",
            data: {
                amount: 0,
                balance: 0,
            },
            methods: {
                specialEvent: function(e) {
                    this.balance += 10000;
                },
                
                ......
                
            }
        })
    </script>

계좌 개설 버튼을 클릭하면 10000원이 잔고에 추가되지만 once 수식어로 인해 한번만 실행됨

 

키코드 수식어

키보드 관련 이벤트를 처리할 때 사용할 수 있는 수식어

    <div id="example" v-cloak>
        <p>
            이름 : <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="contacts">
                <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>
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.auto.min.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el: '#example',
            data: {
                name: "",
                isProcessing: false,
                contactlist: []
            },
            methods: {
                search: function(e) {
                    var 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(response) {
                            return response.json()
                        }).then(function(json) {
                            vm.contactlist = json;
                            vm.isProcessing = false;
                        }).catch(function(ex) {
                            console.log('parsing failed', ex);
                            vm.contactlist = [];
                            vm.isProcessing = false;
                        })

                }
            }
        })
    </script>

if(e.keyCode == 13) { ...... } 대신 v-on:keyup.13 수식어로 엔터 이벤트를 처리

 

vue.js에서 제공하는 키코드 수식어 별칭

.enter .tab .delete .esc
.space .up .down .left
.right .ctrl .alt .shift
.meta      

 

마우스 버튼 수식어

    <div id="example" v-on:contextmenu.prevent="ctxStop"
        @mouseup.left="leftMouse" @mouseup.right="rightMouse">
        <div>
            Left Click : 왼쪽으로<br /> Right Click : 오른쪽으로
        </div>
        <img src="images/foot.jpg"
            v-bind:style="{ position:'absolute', left: pos.left + 'px', top:pos.top +'px' }" />
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#example",
            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!!");
                }
            }
        })
    </script>

마우스 우측 버튼 클릭했을 때 내장 컨텍스트 메뉴가 나타나지 않도록 contextmenu.prevent 수식어 적용

스타일 정보를 적용하기 위해 v-bind:style 사용

 

마우스 버튼 수식어 별칭

.left .right .middle



728x90

'Vue.js' 카테고리의 다른 글

컴포넌트 기초  (0) 2019.05.13
스타일  (0) 2019.05.06
Vue 인스턴스  (0) 2019.04.25
Vue.js 기초  (0) 2019.04.24
Vue.js란?  (0) 2019.04.24
Comments