Vue.js

Vue.js 3.0 STEP 3 - 이벤트 처리

2024. 1. 18. 15:50
728x90

★ 이벤트 처리

  • 동적 UI는 HTML 요소에서 발생하는 이벤트 처리를 통해 구현되는 경우가 많다.
  • Vue의 이벤트는 HTML, 자바스크립트에서 사용하는 이벤트를 준용해서 사용하기 때문이다.

 

1. 인라인 이벤트 처리

  • Vue에서의 이벤트 처리는 아래와 같이 주로 사용한다.
v-on:[이벤트 이름]="표현식"
  • 가장 많이 쓰이는 click 이벤트 예
  • v-on 디렉티브는 @로 줄여 쓸 수도 있다.
v-onclick="test($event)"
@click="test($event)"
<body>
    <div id="app">
        금액 : <input type="text" v-model.number="amount" /><br/>
        <button v-on:click="balance += parseInt(amount)">입금</button>
        <button v-on:click="balance -= parseInt(amount)">출금</button>
        <br />
        <h3>계좌 잔고 : {{ balance }}</h3>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
    var vm = Vue.createApp({
        name : "App",
        data() {
            return { amount : 0, balance : 0 };
        }
    }).mount("#app")
    </script>
</body>

 

 

2. 이벤트 핸들러 메서드

  • Vue 인스턴스에 등록한 메서드를 이벤트 처리 함수로 연결
  • 이와 같이 복잡한 기능은 메서드를 미리 작성해두고, v-on 디렉티브로 참조해서 이벤트를 수행한다.
<body>
    <div id="app">
        금액 : <input type="text" v-model.number="amount"/><br/>
        <button @click="deposit">입금</button>
        <button @click="withdraw">인출</button>
        <br/>
        <h3>계좌 잔고 : {{ balance }} </h3>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
    var vm = Vue.createApp({
        name : "App",
        data() {
            return { amount : 0, balance : 0}
        },
        methods : {
            deposit() {
                let amt = parseInt(this.amount);
                if (amt <= 0) {
                    alert("0보다 큰 값을 예금해야 합니다.");
                } else {
                    this.balance += amt;
                }
            },
            withdraw() {
                let amt = parseInt(this.amount);
                if(amt <= 0) {
                    alert("0보다 큰 값을 인출할 수 있습니다.");
                }else if (amt > this.balance ) {
                    alert("현재 있는 잔고보다 많은 금액을 인출 할 수 없습니다.");
                }else {
                    this.balance -= amt;
                }
            }
        }
    }).mount("#app")
    </script>
</body>
  • 글자에 대한 이벤트 처리
  • 하지만 이 메서드의 기능은 메서드로 처리하기에는 단 한줄의 코드만 실행한다.
<body>
    <div id="app">
        <input id="a" type="text" :value="name" @input="changeName">
        <br />
        입력하신 이름 : <span> {{ name }} </span>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
    var vm = Vue.createApp({
        name : "App",
        data() {
            return { name : "" }
        },
        methods : {
            changeName(e) {
                this.name = e.target.value;
            }
        }
    }).mount("#app")
    </script>
</body>

 

  • 상위 코드는 두가지 방법으로 개선할 수 있다.
  • 1번째 방법 : 인라인 이벤트로 처리
<input id="a" type="text" :value="name" @input="this.name = $event.target.value">
  • 2번째 방법 : 화살표 함수 사용
  • 하지만, 이 방법은 논리 오류가 발생한다.
  • 컴포넌트 인스턴스의 name이 아닌, window.name에 입력한 값이 할당이 된다.
<div id="app">
    <input id="a" type="text" :value="name"
        @input="(e) => this.name = e.target.value ">
    <br />
    입력하신 이름 : <span> {{ name }} </span>
</div>
<script type="text/javascript" src="https://unpkg.com/vue"></script>
<script type="text/javascript">
    var vm = Vue.createApp({
        name : "App",
        data() {
            return { name : "" }
        }
    }).mount("#app")
</script>
</body>
  • 하나의 이벤트에 대해 여러 이벤트 핸들러 메서드가 실행되도록 하는 방법
<button @click="change1($event), change2($event)">두 개의 핸들러 실행</button>

 

 

3. 이벤트 객체

  • 메서드의 첫 번째 인자로 이벤트 객체 e를 전달받을 수 있다.
  • e의 target 속성을 이용해 e.target.value 값을 전달받을 수 있다는 점
  • 전체적인 이벤트 객체의 속성
  • 3.1 이벤트 객체의 주요 공통 속성
속성명 설명
target 이벤트가 발생한 HTML 요소를 리턴함.
currentTarget 이벤트 리스너가 이벤트를 발생시키는 HTML 요소를 리턴함.
path 배열값, 이벤트 발생 HTML 요소로부터 document, window 객체로까지 거슬러 올라가는 경로를 나타냄
bubbles 현재의 이벤트가 버블링을 일으키는 이벤트인지 여부를 리턴함.
cancelable 기본 이벤트의 실행 취소할 수 있는지 여부를 리턴함.
defaultPrevented 기본 이벤트의 실행이 금지되었는지 여부를 나타냄.
eventPhase 이벤트 흐름의 단계를 나타냄.
1. 포착 2.이벤트 발생 3. 버블링
srcElement IE에서 사용되던 속성으로 target과 동일한 속성
  • 3.2 키보드 이벤트 관련 속성
속성명 설명
altKey ALT 키가 눌려졌는지 여부를 나타냄(true/false)
shiftKey SHIFT 키가 눌려졌는지 여부를 나타냄(true/false)
ctrlKey CTRL 키가 눌려졌는지 여부를 나타냄(true/false)
metakey 메타키가 키가 눌려졌는지 여부를 나타냄(true/false), window에서는 window 키
key 이벤트에 의해 나타나는 키의 값을 리턴함. 대소문자 구분
code 이벤트를 발생시킨 키의 코드값을 리턴함.
a를 눌렀을 때, "KeyA"를 리턴함.
keyCode 이벤트를 발생시킨 키보드의 고유 키코드
a,A는 65를 리턴함.
charCode keypress 이벤트가 발생될 때 Union 캐릭터 코드를 리턴함.
  • 3.3 마우스 이벤트 관련 속성
속성명 설명
altkey, shiftkey,
ctrlkey, metakey
키보드 이벤트 관련 속성 참조
button 이벤트를 발생시킨 마우스 버튼 ( 0 : 마우스 왼쪽, 1 : 마우스 휠, 2 : 마우스 오른쪽)
buttons 마우스 이벤트가 발생한 후에 눌러져 있는 마우스 버튼의 값을 리턴함.
(1: 마우스 왼쪽, 2: 마우스 오른쪽, 4: 마우스 휠, 8: 4번째 마우스, 16: 5번째 마우스)
clientX, clientY 마우스 이벤트가 일어났을 때의 영역상의 좌표
layerX, layerY 마우스 이벤트가 발생한 HTML 요소 영역상에서 좌표(IE 이외의 브라우저 사용)
offsetX, offsetY 마우스 이벤트가 발생한 HTML 요소 영역상에서 좌표(IE 브라우저 사용)
pageX, pageY 마우스 이벤트가 일어났을 때의 HTML 문서 영역상의 좌표
screenX, screenY 마우스 이벤트가 일어났을 때의 모니터 화면 영역상의 좌표
  • 3.4 이벤트 객체의 주요 메서드
속성명 설명
preventDefault() 기본 이벤트의 자동 실행을 금지시킴
stopPropagation() 이벤트의 전파를 중단시킴

 

 

4. 기본 이벤트

  • HTML 문서나, 요소에 어떤 기능을 실행하도록 이미 정의되어 있는 이벤트를 기본 이벤트라고 부른다.
  • preventDefault() : 기본 이벤트를 중지시킬 수 있는 방법 
  • ctxStop 메서드 : 무조건 preventDefault() 메서드를 호출한다.
<body>
    <div id="app">
        <div @contextmenu="ctxStop"
            style="position:absolute; top:5px; right:5px; bottom:5px; left:5px;">
            <a href="https://facebook.com" @click="confirmFB">페이스북</a>
        </div>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
    var vm = Vue.createApp({
        name : "App",
        methods : {
            ctxStop(e) {
                e.preventDefault();
            },
            confirmFB(e) {
                if (!confirm("페이스북으로 이동할까요?")) {
                    e.preventDefault();
                }
            }
        }
    }).mount("#app")
    </script>
</body>
  • 하지만, 개발자가 이벤트에 의해 호출되는 메서드에 매번 e.preventDefault()를 작성하도록 신경쓰는 것은 쉽지 않다.
  • 이때 사용하는 것이 이벤트 수식어
  • 이렇게 이벤트명 뒤쪽에 .prevent와 같이 첨부하면 된다.
<div id="app">
	<div @contextmenu.prevent
    	style="position:absolute; top:5px; right:5px; bottom:5px; left:5px;">
        <a href="https://facebook.com" @click="confirmFB">페이스북</a>
    </div>
</div>

 

 

5. 이벤트 전파와 버블링

  • HTML 문서의 이벤트 처리는 3단계를 거친다.
  • 1단계 : 문서 내의 요소에서 이벤트가 발생했을 때 HTML 문서의 밖에서부터 이벤트를 발생시킨 HTML 요소까지 포착해 들어가는 이벤트 포착 단계
  • 2단계 : 이벤트를 발생시킨 요소에 다다르면 요소의 이벤트에 연결된 함수를 직접 호출시키는 이벤트 발생 단계
  • 3단계 : 이벤트가 발생한 요소로부터 상위 요소로 거슬러 올라가면서 동일한 이벤트를 호출시키는 버블링 단계
<body>
    <div id="app">
        <div id="outer" @click="outerClick">
            <div id="inner" @click="innerClick"></div>
        </div>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
    var vm = Vue.createApp({
        name : "App",
        methods : {
            outerClick(e) {
                console.log("## OUTER CLICK");
                console.log("Event Phase : ", e.eventPhase);
                console.log("Current Target : ", e.currentTarget);
                console.log("Target : ", e.target);
            },
            innerClick(e) {
                console.log("## INNER CLICK");
                console.log("Event Phase : ", e.eventPhase);
                console.log("Current Target : ", e.currentTarget);
                console.log("Target : ", e.target);
            }
        }
    }).mount("#app")
    </script>
</body>
  • 하지만, 위 사항은 이벤트 버블링에 의해 두 가지의 버튼이 같이 클릭 됨.
  • 이러한, 이벤트 버블링을 막기 위해,  stopPropagation() 메서드를 이용한다.
  • e.stop : 이벤트 전파를 중단시킨다.
  • e.capture : CAPTURING_PHASE 단계에서만 이벤트가 발생한다.
  • e.self : RAISING_PHASE 단계일 때만 이벤트가 발생한다.
var vm = Vue.createApp({
        name : "App",
        methods : {
            outerClick(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(e) {
                console.log("## INNER CLICK");
                console.log("Event Phase : ", e.eventPhase);
                console.log("Current Target : ", e.currentTarget);
                console.log("Target : ", e.target);
                e.stopPropagation();
            }
        }
    }).mount("#app")
  • 더 간결한 방법
<div id="app">
    <div id="outer" @click.stop="outerClick">
    	<div id="inner" @click.stop="innerClick"></div>
    </div>
</div>
  • 만약, .prevent 수식어 등을 모두 이어 붙여서 사용한다면
<div id="example">
    <div id="outer" @click.capture.stop="outerClick">
    	<div id="inner" @click.stop="innerClick"></div>
    </div>
</div>

 

 

6. 이외의 다양한 이벤트 수식어

  • 6-1. once 수식어
  • 한 번만 이벤트를 발생시키고 이벤트 연결을 해제한다.
<body>
    <div id="app">
        금액 : <input type="text" v-model.number="amount"/> <br>
        <button @click="balance += parseInt(amount)">입금</button>
        <button @click="balance -= parseInt(amount)">출금</button>
        <button @click.once="balance += 10000">계좌 개설 이벤트</button>
        <br>
        <h3>계좌 잔고 : {{ balance }}</h3>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
    var vm = Vue.createApp({
        name : "App",
        data() {
            return { amount : 0, balance : 0 };
        }
    }).mount("#app")
    </script>
</body>
  • 6-2. 키코드 관련 수식어
  • 키보드 관련 이벤트를 처리할 때 사용할 수 있는 수식어.
  • 수식어를 통해 단순한 코드 작성을 줄일 수 있다.
<body>
    <div id="app">
        이름 : <input type="text" v-model.trim="name" @keyup="search"
                    placeholder="영문 두글자 이상을 입력하세요."/><br />
        <ul>
            <li v-for="c in contacts">{{c.name}} : {{c.tel}}</li>
        </ul>
        <div v-show="isLoding">검색중</div>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript" src="https://unpkg.com/axios"></script>
    <script type="text/javascript" src="https://unpkg.com/lodash"></script>
    <script type="text/javascript">
    const BASEURL = "https://contactsvc.bmaster.kro.kr";
    var vm = Vue.createApp({
        name : "App",
        data() {
            return { name : "", contacts : [], isLoding : false}
        },
        methods : {
            search(e) {
                if (e.keyCode == 13) {
                    if (this.name.length >=2) {
                        this.fetchContacts();
                    } else {
                        this.contacts = [];
                    }
                }
            },
            fetchContacts : _.debounce(function() {
                this.isLoding = true;
                axios.get(BASEURL + `/contacts_long/search/${this.name}`)
                .then((response)=>{
                    this.isLoding = false;
                    this.contacts = response.data;
                })
            }, 300)
        }
    }).mount("#app")
    </script>
</body>
  • 위와 같은 방식으로  keyCode를 사용해도 되지만, 수식어를 사용하는 편이 훨씬 더 편리하다.
이름 : <input type="text" v-model.trim="name" @keyup.enter="search"/>
//위와 동일
<script>
//위와 동일
var vm = Vue.createApp({
    methods : {
    	search() {
            if(this.name.length >=2) {
            	this.fetchContacts();
            } else {
            	this.contacts = [];
            }
        },
        	.......
    }
}).mount("#app")
</script>
  • .enter와 같은 키코드 이외에도 다양한 키코드 관련 수식어가 존재함.
.up .down .left .right
.enter .tab .delete .esc
.space .ctrl .alt .shift
.meta      
  • 6-3. 마우스 관련 수식어
  • 마우스 버튼 수식어를 사용해, 마우스 왼쪽, 오른쪽 버튼을 클릭해서 목록에서 선택
.left .right .middle
  • currentIndex 값과 v-for 디렉티브를 이용해 목록을 반복 렌더링할 때의 index 값이 같을 때만, 화살표 아이콘 모양을 출력하고, active 클래스가 주어지도록 v-if 디렉티브를 사용한다.
<head>
    <meta charset="UTF8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>05-13</title>
    <link rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css"/>
    <link rel="stylesheet" href="https://unpkg.com/font-awesome@4.7.0/css/font-awesome.min.css">
</head>
<body>
    <div id="app">
        <div class="container" 
            style="position:absolute; top:0; left:0; bottom:0; right: 0;"
            @contextmenu.prevent @click.left="if (currentIndex > 0) currentIndex--;"
            @click.right="if (currentIndex < itemlist.length-1) currentIndex++;"
            @click.ctrl.left="currentIndex=0"
            @click.ctrl.right="currentIndex=itemlist.length-1">
        <div>
            - 왼쪽 버튼 : 위로 <br/>
            - 오른쪽 버튼 : 아래로 <br>
            - CTRL + 왼쪽 버튼 : 처음으로 <br />
            - CTRL + 오른쪽 버튼 : 마지막으로 <br />
        </div>
        <hr />
            <ul class="list-group">
                <li class="list-group-item"
                    :class="index === currentIndex ? 'active' : ' ' "
                    v-for="(item, index) in itemlist" :key="item">
                    {{item}}
                    <span v-if="index === currentIndex"
                        className="float-right badge badge-secondary">
                        <i class="fa fa-arrow-left" aria-hidden="true"></i>
                    </span>
                </li>
            </ul>
        </div>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
    var vm = Vue.createApp({
        name : "App",
        data() {
            return {
                itemlist : ["Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9"],
                currentIndex : 0,
            };
        }
    }).mount("#app")
    </script>
</body>
  • 6-4. exact 수식어
  • exact 수식어는 다른 시스템 수식어와 조합해 이벤트를 등록할 때 정확하게 일치하는 조합으로 이벤트가 일어나야 핸들러가 실행되도록 설정한다.
<body>
    <div id="app">
        <ul>
            <li>마우스 왼쪽만 클릭 : 1씩 증가</li>
            <li>CTRL+왼쪽 클릭 : 10씩 증가</li>
            <li>CTRL+ALT+왼쪽 클릭 : 100씩 증가</li>
        </ul>
        <button @click="num=num+1" @click.ctrl="num=num+10" @click.ctrl.alt="num=num+100">
            클릭하세요!
        </button>
        <br>
        <h3>카운트 : {{num}}</h3>
    </div>
    <script type="text/javascript" src="https://unpkg.com/vue"></script>
    <script type="text/javascript">
    var vm = Vue.createApp({
        name: "App",
        data() {
            return { num : 0 };
        }
    }).mount("#app");
    </script>
</body>
  • 이렇게 작성하게 되면, CTRL+ALT+왼쪽 을 누르게 되면 100이 증가되는 것이 아니라, 세가지가 모두 해당 됨으로, 111이 증가가 된다. 이럴때, exact 수식어를 사용하면 된다.
<button @click.exact="num=num+1" @click.ctrl.exact="num=num+10" @click.ctrl.alt.exact="num=num+100">

 

728x90
저작자표시 비영리 변경금지 (새창열림)

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

Vue.js 3.0 STEP 5 - TodoList  (0) 2024.01.25
Vue.js 3.0 STEP 4 - 스타일 적용  (0) 2024.01.25
Vue.js 3.0 STEP 2 - Vue 인스턴스  (0) 2024.01.18
Vue.js 3.0 STEP 1 - Vue.js 기초와 Template  (0) 2024.01.17
ES6 STEP 2 - 기본 문법 2  (0) 2024.01.17
'Vue.js' 카테고리의 다른 글
  • Vue.js 3.0 STEP 5 - TodoList
  • Vue.js 3.0 STEP 4 - 스타일 적용
  • Vue.js 3.0 STEP 2 - Vue 인스턴스
  • Vue.js 3.0 STEP 1 - Vue.js 기초와 Template
IT의 큰손
IT의 큰손
IT계의 큰손이 되고 싶은 개린이의 Log 일지
IT의 큰손
Developer Story House
IT의 큰손
전체
오늘
어제
  • 분류 전체보기 (457)
    • 정보처리기사 필기 (18)
    • 정보처리기사 실기 (12)
    • 정보처리기사 통합 QUIZ (12)
    • 빅데이터 (11)
    • 안드로이드 (11)
    • 웹페이지 (108)
    • 자바 (49)
    • SQLD (3)
    • 백준 알고리즘 (76)
    • 데이터베이스 (41)
    • 깃허브 (2)
    • Library (14)
    • Server (31)
    • 크롤링&스크래핑 (3)
    • Spring (23)
    • Vue.js (13)
    • React (27)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • Developer Stroy House

인기 글

태그

  • 정보보안전문가
  • IT개발자
  • 앱개발자
  • 웹페이지
  • 알고리즘
  • DBA
  • 자바
  • jsp
  • jquery
  • JavaScript
  • html
  • 정보처리기사필기
  • IT자격증공부
  • 정보처리기사
  • 데이터베이스
  • 프론트엔드
  • 웹개발자
  • 개발블로그
  • React
  • 백엔드
  • IT자격증
  • java
  • 백준
  • it
  • 웹개발
  • ajax
  • 코딩테스트
  • 개발자
  • DB
  • css

최근 댓글

최근 글

Designed By hELLO
IT의 큰손
Vue.js 3.0 STEP 3 - 이벤트 처리
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.