티스토리 뷰

Vue

Vue.js 이벤트 처리

인삼추출물 2021. 2. 25. 09:27

(공부 책 : Vue.js Quick Start )

1. 인라인 이벤트 처리

Vue.js에서 이벤트는 v-on 디렉티브를 이용해 처리 가능합니다. 

<body>
    <div id="example" class="container layout1">
        <p><input type="text" v-model="money" class="form-control" /></p>
        <p>
            <button id="deposit" v-on:click="account += parseInt(money)" 
            class="btn btn-primary">입금</button>
            <button id="withdraw" v-on:click="account -= parseInt(money)" 
            class="btn btn-primary">인출</button>
        </p>
        <h3>계좌 잔고 : {{account}}</h3>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#example",
            data: {
                money: 0,
                account: 0
            }
        })
    </script>
</body>

v-model로 money 속성을 양방향 바인딩하고 money의 값에 따라 account의 양이 변하게

button에서 v-on 디렉티브를 이용하여 click 이벤트 처리로 값이 증, 차감 되도록 합니다.

( ※ v-on:click은 @click으로도 대체 가능합니다. )

위 예제 코드의 경우 account의 값을 변화시키는 작업이 html 인라인에서 직접 이루어지고 있습니다.

만약 '계좌 금액은 마이너스로 갈 수 없다' 등과 같은 특수한 조건이 붙는다면 모든 조건을 인라인 이벤트 처리로 작성하기엔 현실적으로 어려울 것 입니다.

 

2. 이벤트 핸들러 메서드

위 예제의 인라인 이벤트를 Vue 인스턴스에 등록한 메서드로 연결되도록 코드를 바꿔봅시다.

<body>
    <div id="example" class="container layout1">
        <p><input type="text" v-model="money" class="form-control" /></p>
        <p>
            <button id="deposit" v-on:click="deposit" class="btn btn-primary">입금</button>
            <button id="withdraw" v-on:click="withdraw" class="btn btn-primary">인출</button>
        </p>
        <h3>계좌 잔고 : {{account}}</h3>
    </div>

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

'계좌 금액은 마이너스로 갈 수 없다'

'0은 입금이나 출금이 불가능하다'

메서드에 연결함으로써 위와같이 좀 더 복잡한 조건을 부담없이 작성할 수 있게 되었습니다.

 

3. 기본 이벤트

몇몇 HTML 요소는 개발자가 이벤트 처리를 하지 않아도 특수한 기능을 실행하는 것들이 있습니다.

<a> tag의 경우 클릭 이벤트를 처리하지 않았으나 클릭하면 href 특성에 의해 정의된 경로로 이동시킵니다.

이와 같이 HTML 문서나 어떤 기능을 실행하도록 이미 정되어 이는 이벤트를 기본 이벤트라 합니다.

이러한 기능은 따로 이벤트 처리를 하지 않아도 된다는 점에서 편리함을 제공하나 때론 걸림돌이 되기도 합니다.

따라서 기본 이벤트 실행을 중지시키는 방법을 알아둘 필요가 있습니다.

<body>
    <div id="example" v-on:contextmenu="ctxStop">
        <a href="https://www.naver.com" @click="changeUrl">네이버</a>
    </div>
    <script type="text/javascript">
        var vm = new Vue({
            el: "#example",
            methods: {
                ctxStop: function(e) {
                    e.preventDefault();
                },
                changeUrl: function(e) {
                    if (!confirm("네이버로 이동할까요?")) {
                        e.preventDefault();
                    }
                }
            }
        })
    </script>
</body>

preventDefault()는 기본 이벤트 실행을 막아주는 함수입니다.

changeUrl() 함수는 사용자의 확인을 받기 위해 confrim() 함수를 사용합니다.

confrim() 함수로부터 false가 return된다면 <a> tag를 실행하는 걸 막도록 preventDefault()를 실행시킵니다.

ctxStop() 함수는 모조건 preventDefault() 함수를 실행시킵니다. 

그러면 우측 클릭으로 발생하는 내장 컨테스트 메뉴가 나타나지 않게 되는데 이는 내장 컨테스트가 아닌 개발자가 직접 작성한 메뉴를 나타내기 위해 쓰이는 경우가 많습니다.

하지만 매번 개발자가 메서드에 e.preventDefault()를 신경써서 작성하기가 쉽지 않습니다.

이를 좀더 쉽게 하기위해 이벤트 수식어라는 것을 제공하는데 

ctxStop: function(e) {
           e.preventDefault();
}

대신

<div id="example" v-on:contextmenu.prevent="ctxStop">

로 대체하여 사용가능합니다.

 

4. 이벤트 전파와 버블링

HTML 문서의 이벤트 처리는 3단계를 거칩니다.

1단계(이벤트 포착 단계)

- 문서 내 요소에서 이벤트가 발생했을 때 HTML 문서의 밖에서부터 이벤트를 발생시킨 요소까지 포착해 들어가는 단계

2단계(이벤트 발생 단계)

- 이벤트를 발생시킨 요소에 이르면 연결된 함수를 직접 호출시키는 단계

3단계(버블링 단계)

- 이벤트가 발생한 요소로부터 상위 요소로 거슬러 올라가면서 동일한 이벤트를 호출시키는 단계

위 단계를 실제 코드로 알아보도록 합시다.

<body>
    <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);
                },
                innerClick: function(e) {
                    console.log("### INNER CLICK")
                    console.log("Event Phase : ", e.eventPhase);
                    console.log("Current Target : ", e.currentTarget);
                    console.log("Target : ", e.target);
                }
            }
        })
    </script>
</body>

outer 클릭 시
inner 클릭 시

결과에서 보여주듯 inner를 클릭해도 outer 이벤트가 같이 실행되는 것을 확인할 수 있습니다.

inner 클릭 이벤트 결과를 보면 outer 이벤트 실행 시 target과 current target이 다릅니다.

이는 버블링 단계에서는 target이 이벤트가 일어난 원본 요소를 가리키기 때문에 생긴 현상입니다.

하지만 일반적으로 이벤트 버블링은 막아야할 작업입니다.

이를 위해 stopPropagation()을 활용해 이벤트 버블링을 막습니다.

                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();
                },

위와 같이 코딩을 하거나 이벤트 수식어를 활용할 수도 있습니다.

.stop: 이벤트 전파를 중단시킵니다.

.capture: 포착 단계에서만 이벤트가 발생합니다.

.self: 발생 단계에서만 이벤트가 발생합니다.

수식어를 @Click.self.stop 과 같이 붙여서 사용 가능합니다.

'Vue' 카테고리의 다른 글

Vue.js 컴포넌트 기초 - 1  (0) 2021.05.14
Vue.js 스타일  (0) 2021.03.25
Vue 인스턴스  (0) 2021.01.29
Vue.js 기타 디렉티브와 계산형 속성  (0) 2021.01.22
Vue.js 반복 렌더링 디렉티브  (0) 2021.01.12
댓글
공지사항