<template>
<header>
<h1>Vue Events</h1>
</header>
<section id="events">
<h2>Events in Action</h2>
<button v-on:click="this.counter++">Add</button>
<button v-on:click="this.counter--">Reduce</button>
<p>Result: {{ counter }}</p>
</section>
</template>
<script>
export default {
name: 'EventBinding',
data() {
return {
counter: 0
}
}
}
</script>
이 코드에는 아쉬운 부분이 있다.
HTML 코드에 로직을 많이 넣으면 안되고, 출력에 집중해야 한다.
로직은 JavaScript 코드에 구현해야 한다.
<template>
<header>
<h1>Vue Events</h1>
</header>
<section id="events">
<h2>Events in Action</h2>
<button v-on:click=addCounter>Add</button>
<button v-on:click=reduceCounter>Reduce</button>
<p>Result: {{ counter }}</p>
</section>
</template>
<script>
export default {
name: 'EventBinding',
data() {
return {
counter: 0
}
},
methods: {
addCounter() {
this.counter++
},
reduceCounter() {
this.counter--
}
}
}
</script>
이때의 메서드는 동적으로 출력하는 것이 아니라, 클릭시 실행되도록 하는 것이므로 아무것도 return할 필요 없다.
이처럼 HTML은 출력에만 집중하고 로직은 JavaScript에서 구현되어야 한다.
이번에는 더하고 빼는 숫자를 파라미터로 넘겨보자!
<button v-on:click=addCounter(5)>Add</button>
<button v-on:click=reduceCounter(5)>Reduce</button>
methods: {
addCounter(num) {
this.counter = this.counter + num;
},
reduceCounter(num) {
this.counter = this.counter - num;
}
}
개발자가 html에서 매개변수의 값을 알려 동적으로 변화시킬 수 있다.
이처럼 때때로 메서드에 매개변수가 필요할 경우 개발자가 설정할 수 있다.
네이티브 이벤트 객체(Native Event Object)란?
- 웹 애플리케이션에서 발생하는 이벤트에 대한 정보를 담고 있는 JavaScript 객체입니다.
- 웹 페이지나 모바일 앱에서 사용자의 동작(클릭, 터치 등)이나 브라우저 내부의 상태 변화(로드, 스크롤, 리사이즈 등)와 같은 이벤트가 발생하면, 브라우저는 해당 이벤트에 대한 정보를 JavaScript 이벤트 객체로 생성하여 이벤트 핸들러에 전달
<input type="text">
<p>Your Name: {{ }} </p>
사용자가 입력란에 이름을 입력하면 밑에 입력값을 출력하도록 만들어 보자!
v-on:keyup, keydown
은 그같은 이벤트의 예시가 될 수 있으나, input 이벤트가 최고의 선택지일 수 있다.
v-on:input="실행할 이벤트 코드 입력"
<input>
에서 이 이벤트를 사용하여 변화를 Vue에 알릴 수 있다. 즉, input값 변화 발생(키 입력 시) 시 이벤트가 시행된다.<input type="text" v-on:input="setName">
<p>Your Name: {{ }} </p>
methods: {
setName() {
this.name =
},
}
🧐 이벤트를 수신하므로 사용자의 입력여부는 알 수 있다. (사용자가 키를 입력할 때 마다 실행되도록 메서드를 만들었다.)
그렇다면 사용자가 입력한 구체적인 값은 어떻게 알 수 있을까?
JavaScript가 제공하는 멋진 기능을 사용할 수 있다. Vue의 기능은 아니지만, Vue에서도 사용할 수 있다. 이벤트 리스너를 추가하고 이벤트 발생 시 실행될 함수를 가리키면 그 함수가 자동으로 (브라우저에서 제공하는) 인수를 하나 얻는다. 그 인수는 발생한 이벤트를 설명하는 객체가 된다.
<button v-on:click = add(5)>Add</button>
<button v-on:click = reduce(5)>Reduce</button>
<input type="text" v-on:input = "setName">
methods: {
setName(event) {
this.name = event.target.value; // 사용자가 입력한 값
},
add(num) {
this.counter = this.counter + num;
},
reduce(num) {
this.counter = this.counter - num;
}
add(), reduce()의 경우 (인수를 받는 대신) 우리가 전달한 사용자 지정 인수로 덮어쓰기를 했다.
그러나 setName의 경우, 괄호를 써서 실행하는 대신 가리키고 있기 때문에 덮어쓰지 않고 브라우저가 기본 이벤트 객체를 제공하도록 한다.
<input type="text" v-on:input="setName">
<p>Your Name: {{ name }}</p>
methods: {
setName(event) {
this.name = event.target.value; // 사용자가 입력한 값 추적
}
}
이 이벤트 객체는 다양한 이벤트 정보로 가득한데, 그 중 HTML 요소에 대한 정보인 input 입력 요소 또한 제공한다. event.target
이라는 순수 JavaScript 기능을 제공하는데, 여기서 그것이 입력 요소이며 value 프로퍼티를 가지고 있다.
(https://developer.mozilla.org/ko/docs/Web/HTML/Element/input 여기서 value 프로퍼티에 관한 정보를 확인할 수 있다.)
결과적으로, 키가 입력될 때 마다 setName이 호출되고, 데이터 프로퍼티인 name이 키가 입력될 때 마다 사용자가 현재 입력한 값으로 업데이트 되게 된다.
.
.
.
이것이 Vue의 반응성이 작용하는 원리이다. 이벤트를 수신하게 해서 코드를 실행하고, 특정 프로퍼티(name)이 변경되면 이를 탐지하여 페이지상 필요한 곳에 업데이트 한다.
실제로 크롬의 개발자 도구를 확인해보면 브라우저에 의해 리렌더링 된 부분이 깜빡이는 것을 확인할 수 있다. 그러나 화면의 다른 곳은 전혀 깜빡이지 않는다. 뷰는 코드에서 진짜로 변경된 부분만 화면에서 리렌더링 한다. 뷰가 전체 화면을 업데이트하면 부분적인 변화에도 성능이 떨어지게 된다. 그러나 Vue는 영리하게 키 입력이 바뀌는 부분만 찾고, 그 부분만 변경한다. 고로 더 좋은 성능을 발휘 할 수 있다.
<template>
<header>
<h1>Vue Events</h1>
</header>
<section id="events">
<h2>Events in Action</h2>
<button v-on:click=addCounter(5)>Add</button>
<button v-on:click=reduceCounter(5)>Reduce</button>
<p>Result: {{ counter }}</p>
<input type="text" v-on:input="setName">
<p>Your Name: {{ name }}</p>
</section>
</template>
<script>
export default {
name: 'EventBinding',
data() {
return {
counter: 0,
name: ''
}
},
methods: {
setName(event) {
this.name = event.target.value; // 사용자가 입력한 값
},
addCounter(num) {
this.counter = this.counter + num;
},
reduceCounter(num) {
this.counter = this.counter - num;
}
}
}
</script>
event 객체에 대해 하나 더 짚고 넘어가보자!
방금 예시에서는 setName 메서드를 가르키기만 함으로써 브라우저가 event객체를 넣어주었다.
<input type="text" v-on:input="setName('Lee')">
<p>Your Name: {{ name }}</p>
methods: {
setName(lastName) {
this.name = event.target.value + ' ' + lastName;
}
}
🧐 근데 만약 내가 메서드에 파라미터를 넣어서 사용하고 싶다면 어떻게 해야 할까? add(5), reduce(5) 처럼 사용자 지정 인수로 이벤트 인수를 덮어써버리면 어떻게 이벤트 인수를 사용할 수 있을까?
앞서 짠 코드 add()처럼 메서드를 명시적으로 호출하고 싶을 수 있다. 인수를 명시하면서 동시에 이벤트 인수를 사용하고 싶은 경우, $event
를 사용할 수 있다.
<input type="text" v-on:input="setName($event,'Lee')">
methods: {
setName(event, lastName) {
this.name = event.target.value + ' ' + lastName;
},
}
이벤트와 메소드를 연결할 때는 v-on
<태그명 v-on:이벤트 = "메소드명>
메소드(명령문)는 Vue 인스턴스에 methods 옵션을 추가해서 만든다.
<template>
<header>
<h1>Vue Events</h1>
</header>
<section id="events">
<h2>Events in Action</h2>
<button v-on:click=addCounter(5)>Add</button>
<button v-on:click.right=reduceCounter(5)>Reduce</button>
<p>Result: {{ counter }}</p>
<input type="text" v-on:input="setName($event,'Lee')">
<button v-on:click=handleClick>얏호응</button>
<p>Your Name: {{ name }}</p>
<form>
<input type="text">
<button>Sign Up</button>
</form>
</section>
</template>
코드를 이런 방식으로 짜면 어떻게 될까?
SignUp 버튼을 클릭하면 페이지가 새로고침 된다.(고로 작성중이던 form 외의 다른 부분까지 날아가버린다!) 브라우저 기본 설정이 버튼이 있는 양식을 제출하며 이 앱을 제공하는 서버에 HTTP 요청을 보내는데, (지금 우리는 서버없이 로컬 환경에서 실행함에도 불구하고) 브라우저가 로컬 기기로 요청을 보내기 때문이다.
일반적으로 Vue같은 프레임워크를 이용할때는 이런 브라우저 기본값이 아니라 수동으로 Vue앱에서 JavaScript로 처리한다. 사용자 입력값을 읽고 유효성을 검사한 뒤 수동으로 백엔드 서버에 요청을 보내 DB에 저장하는 방식으로 말이다.
따라서, 브라우저가 요청을 자동으로 전송하는 기본값을 방지해야 한다!
<form v-on:submit="submitForm">
<input type="text">
<button>Sign Up</button>
</form>
submitForm(event) {
event.preventDefault();
}
내장된 수식어를 사용하여 이벤트 동작을 바꿀 수 있다.
<form v-on:submit.prevent="submitForm">
이벤트 이름 뒤에 마침표를 찍는다.
지원되는 수식어가 제한되어 있다.(공식 문서에서 확인가능)
.prevent
: Vue에 내장. 브라우저 기본값 방지.
<button v-on:click.right=reduceCounter(5)>Reduce</button>
이벤트 트리거 변경 : 마우스 우클릭에 버튼이 작동하도록 변경
지금까지는 <input>
을 통해 모든 키보드 입력에 반응하는 코드를 만들었다. (v-on:key와 동일한) 이번에는 enter에 반응하도록 수정해보자!
<input type="text"
v-on:input="setName($event,'Lee')"
v-on:keyup="confirmInput">
<button v-on:click=handleClick>input</button>
data() {
return {
counter: 0,
name: '',
confirmedName: ''
}
},
methods: {
confirmInput() {
this.confirmedName = this.name;
}
}
여기까지가 앞서 작성했던 v-on:input
과 동일한 코드이다.
여기서 key에 .enter
이라는 수식어를 제공함으로써 엔터를 클릭해야만 렌더링이 이루어지도록 변경할 수 있다!
<input type="text"
v-on:input="setName($event,'Lee')"
v-on:keyup.enter="confirmInput">
특정 콘텐츠에 대한 값은 유지하고 싶은 경우가 있을 수 있다.
<p>Starting Counter: {{ counter }}</p>
<p>Result: {{ counter }}</p>
data() {
return {
counter: 10
}
},
<p v-once>Starting Counter: {{ counter }}</p>
카운터가 변경되더라도 일부 데이터만 변경하고 초기 상태는 유지하면서 상태를 변경하지 않으려면, v-once
디렉티브를 사용할 수 있다.
이후에 값이 바뀌어도 v-once 디렉티브가 적용되어 있는 부분은 보간법, 동적 바인딩을 한 번만 수행도록 제한한다.