VueJS
- https://joshua1988.github.io/vue-camp/
- https://v3.ko.vuejs.org/
- http://www.yes24.com/Product/Goods/101926719
사용자 입력
<div id="event-handling">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">Reverse Message</button>
</div>
const EventHandling = {
data() {
return {
message: 'Hello Vue.js!'
}
},
methods: {
reverseMessage() {
this.message = this.message
.split('')
.reverse()
.join('')
}
}
}
v-on:event
를 통해서 이벤트를 제어 한다.
<input @keyup.enter="submit" />
vuejs에서는 기본적인 key 이벤트를 제공한다.
- enter
- tab
- delete
- esc
- space
- up
- down
- left
- right
Vue는 또한 양식에 대한 입력과 앱 상태를 양방향으로 바인딩하는 v-model
디렉티브를 제공한다.
<div id="two-way-binding">
<p>{{ message }}</p>
<input v-model="message" />
</div>
const TwoWayBinding = {
data() {
return {
message: 'Hello Vue!'
}
}
}
양방향 바인딩이 뭔지 좀 더 찾아봐야 한다. react는 단반향 바인딩만 지원 하기 때문에, vuejs랑 다르다.
Model에서 데이터를 정의한 후 View와 연결하면 Model, View 중 어느 한쪽에서 변경이 일어났을 때, 다른 한쪽에 자동으로 반영 되는 것을 데이터 양방향 바인딩이라고 한다.
조건문과 반복문
<div id="conditional-rendering">
<span v-if="seen">이제 나를 볼수 있어요</span>
</div>
const ConditionalRendering = {
data() {
return {
seen: true
}
}
}
조건문의 경우 v-id
를 이용하면 된다. Vue 엘리먼트가 Vue에 삽입/업데이트/제거 될때 자동으로 전환 효과 적용 된다고 한다. ref. https://v3.ko.vuejs.org/guide/transitions-enterleave.html
<div id="list-rendering">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</div>
const ListRendering = {
data() {
return {
todos: [
{ text: 'Learn JavaScript' },
{ text: 'Learn Vue' },
{ text: 'Build something awesome' }
]
}
}
}
v-for
는 반복문 directive이다. 반복문 시에는 v-bind:key
를 필수적으로 지정 해주어야 한다.
컴포넌트 조립
const TodoList = {
data() {
return {
groceryList: [
{ id: 0, text: '야채' },
{ id: 1, text: '치즈' },
{ id: 2, text: '사람이 먹을수 있는거라면 뭐든지' }
]
}
}
}
const app = Vue.createApp(TodoList)
app.component('todo-item', {
props: ['todo'],
template: `<li>{{ todo.text }}</li>`
})
app.mount('#todo-list-app')
<div id="todo-list-app">
<ol>
<!--
이제 할일 todo-item 에 할일을 전달합니다.
콘텐츠는 동적으로 포현됩니다.
여기에서 "key"를 또 전달하고 있는데
이것에 대해서는 나중에 설명하겠습니다.
-->
<todo-item
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id"
></todo-item>
</ol>
</div>
컴포넌트에 v-bind
를 통해서 데이터를 전달 할 수 있다.
<template>
</template>
<script>
export default {
name: '' // 컴포넌트 이름
components: {}, // 외부 컴포넌트를 사용하게 되면, 해당 컴포넌트를 import한 후 등록 해주어야 한다.
data() {
return {
};
}, // 전역 데이터 선언 (html, js간의 양방향 데이터 바인딩 가능하며, 데이터 프로퍼티에서는 this로 접근 해야 한다.)
setup() {}, // 컴포지션 API를 구현하는 메소드
created() {}, // 컴포넌트 생성시, 실행
mounted() {}, // template에 정의된 html코드가 렌더링 된 후 실행
unmounted() {}, // unmount 이후 실행
methods: {} // 컴포넌트 내에서 사용할 메소드 정의
}
</script>
문자열 데이터 바인딩
<h1>Hello, {{ title }}</h1>
{{}}
로 감싸주면 된다.
<h1 v-once>Hello, {{ title }}</h1>
v-once
디렉티브를 사용하면, 데이터가 변경 되어도 갱신 되지 않는 렌더를 보장 할 수 있으나, 같은 노드의 바인딩에도 영향을 준다.
raw HTML 데이터 바인딩
<template>
<h1>Hello, {{ title }}</h1>
<div v-html="htmlString"></div>
</template>
<script>
export default {
data() {
return {
title: "DataBinding",
htmlString: '<p style="color:red">This is a red string</p>'
}
}
}
</script>
v-html
디렉티브를 사용하면 html도 렌더링시 적용 되도록 할 수 있다.
<div v-bind:id="dynamicID"></div>
이중 중괄호 구문은 HTML 속성에 사용할 수 없다. 대신, v-bind
를 사용할 수는 있다.
전달 인자
일부 디렉티브는 디렉티브 명 뒤에 콜론으로 표기되는 전달인자를 가질 수 있다.
<a v-bind:href="url"></a>
동적 전달인자
<a v-bind:[attributeName]="url"></a>
JavaScript 표현식을 대괄호로 묶어 디렉티브 전달인자로 사용할 수 있다.
동적인자는 null을 제외하고 string으로 변환되어야 한다.
<!-- 컴파일러 경고가 발생합니다. -->
<a v-bind:['foo' + bar]="value"> ... </a>
위와 같은 경우 computed 속성을 이용하면 된다. ref. https://v3.ko.vuejs.org/guide/computed.html#%E1%84%80%E1%85%B5%E1%84%87%E1%85%A9%E1%86%AB-%E1%84%8B%E1%85%A8%E1%84%8C%E1%85%A6
<!--
in-DOM 템플릿에서는 이 부분이 v-bind:[someattr]로 변환됩니다. 인스턴스에 "someattr" 속성이 없는 경우, 이 코드는 동작하지 않습니다.
-->
<a v-bind:[someAttr]="value"> ... </a>
수식어
디렉티브를 특별한 방법으로 바인딩해야 함을 나타낸다.
<form v-on:submit.prevent="onSubmit"></form>
.prevent
의 경우 트리거 된 이벤트에서 event.preventDefault()
를 호출하도록 명시하는 것이다.
약어
v-bind
, v-on
에 대한 약어를 제공한다.
<!-- 전체 문법 -->
<a v-bind:href="url"> ... </a>
<!-- 약어 -->
<a :href="url"> ... </a>
<!-- 동적 전달인자와 함께 쓴 약어 -->
<a :[key]="url"> ... </a>
<!-- 전체 문법 -->
<a v-on:click="doSomething"> ... </a>
<!-- 약어 -->
<a @click="doSomething"> ... </a>
<!-- 동적 전달인자와 함께 쓴 약어 -->
<a @[event]="doSomething"> ... </a>
v-if, v-show 차이
v-if는 조건식이 맞지 않으면, html 블록 자체가 생성 되지 않는다. 그런데, v-show는 일단 html 블록은 생성 되지만, 조건에 따라 display를 이용하는 차이가 있다.
어플리케이션 & 컴포넌트 인스턴스
모든 Vue 어플리케이션은 createApp
함수를 사용하여 새로운 어플리케이션 인스턴스를 생성하여 시작한다.
const RootComponent = {}
const app = Vue.createApp({})
const vm = app.mount('#app')
어플리케이션 인스턴스에 의해 노출된 대부분의 메소드들은 동일한 인스턴스를 반환하여 chaining을 허용한다.
다만, mount() 함수의 경우 어플리케이션을 반환하지 않고, 루트 컴포넌트 인스턴스를 반환 한다.
라이프 사이클 훅
각 컴포넌트는 생성될 때 일련의 초기화 단계를 거친다. 모든 라이프 사이클 훅에서는 Vue인스턴스를 가리키는 this context와 함께 호출 된다.
options 속성이나 콜백에서 created: () => console.log(this.a)
와 같은 arrow function을 사용하지 않는다. 이유는 arrow function은 context를 function 내부로 한정 하기 때문에, this가 없어서 this를 parent scope까지 모두 찾다가 없으면 오류를 발생시킨다.
Data 속성 / Method
컴포넌트의 data 옵션은 함수다. Vue는 새로운 컴포넌트 인스턴스 생성의 일환으로 data 함수를 호출한다.
const app = Vue.createApp({
data() {
return { count: 4 }
}
})
const vm = app.mount('#app')
console.log(vm.$data.count) // => 4
console.log(vm.count) // => 4
새로운 속성을 data
에 포함하지 않고 컴포넌트 인스턴스에 직접 추가할 수 있습니다. 하지만, 이렇게 추가한 속성은 반응형 $data
객체로 처리되지 않기 때문에 Vue의 반응형 시스템에 의해 자동으로 추적되지 않습니다.
컴포넌트 인스턴스에 메서드를 추가하려면 methods
옵션을 사용하세요. methods
옵션은 동작하기를 원하는 메서드들이 담긴 하나의 객체여야 합니다.
const app = Vue.createApp({
data() {
return { count: 4 }
},
methods: {
increment() {
// `this`는 컴포넌트 인스턴스를 참조합니다.
this.count++
}
}
})
const vm = app.mount('#app')
console.log(vm.count) // => 4
vm.increment()
console.log(vm.count) // => 5
Vue는 methods
안에서 컴포넌트 인스턴스를 항상 참조할 수 있도록 this
값을 자동으로 바인딩합니다. 이렇게 하면 메서드가 이벤트 리스너나 콜백으로 사용될 때, 올바른 this
값을 유지하게 됩니다. 화살표 함수를 사용해서 methods
를 정의하면 Vue가 적절한 this
값을 바인딩하지 못합니다. 따라서 methods
를 정의할 때, 화살표 함수를 사용하지 않도록 합니다.
Computed 속성 / watch
<div id="computed-basics">
<p>출판된 책:</p>
<span>{{ publishedBooksMessage }}</span>
</div>
Vue.createApp({
data() {
return {
author: {
name: '존 도우',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
}
}
},
computed: {
// computed getter
publishedBooksMessage() {
// 여기서의 `this` 는 vm 인스턴스이다.
return this.author.books.length > 0 ? '있음' : '없음'
}
}
}).mount('#computed-basics')
computed 속성 대신에 메서드와 동일한 함수를 정의할 수 있습니다. 최종 결과를 위해, 두가지 접근 방식은 정확히 동일합니다. 그러나 차이점은 computed 속성은 반응형(reactive) 종속성에 기반하여 캐시된다는 것 입니다. computed 속성은 반응형 종속성 중 일부가 변경된 경우에만 재평가됩니다. 즉, author.books
가 변경되지 않는다면 publishedBooksMessage
computed 속성에 대해 여러번 접근하더라도 함수를 다시 실행할 필요없이 이전에 계산된 결과를 즉시 반환합니다.
Watch
데이터 변경에 대한 응답으로 비동기 혹은 비용이 많이 드는 작업을 수행하려는 경우가 가장 유용합니다.
<!-- 이미 Ajax 라이브러리의 풍부한 생태계와 범용 유틸리티 메소드 컬렉션이 있기 때문에, -->
<!-- Vue 코어는 다시 만들지 않아 작게 유지됩니다. -->
<!-- 이것은 이미 익숙한 것을 선택할 수 있는 자유를 줍니다. -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script>
const watchExampleVM = Vue.createApp({
data() {
return {
question: '',
answer: '질문은 보통 물음표를 포합합니다. ;-)'
}
},
watch: {
// question 이 변경될 때마다, 이 함수가 실행될 것 입니다.
question(newQuestion, oldQuestion) {
if (newQuestion.indexOf('?') > -1) {
this.getAnswer()
}
}
},
methods: {
getAnswer() {
this.answer = '생각중...'
axios
.get('https://yesno.wtf/api')
.then(response => {
this.answer = response.data.answer
})
.catch(error => {
this.answer = '에러! API에 닿지 못했습니다. ' + error
})
}
}
}).mount('#watch-example')
</script>
'프로그래밍 > JavaScript' 카테고리의 다른 글
VueJS 학습 - TypeScript 사용 (0) | 2022.10.13 |
---|---|
VueJS 학습 - Component (0) | 2022.10.13 |
vuejs minimizer 설정 변경 (0) | 2022.09.16 |
vite build 오류 (0) | 2022.09.07 |
코드스피츠 77 - ES6+ 기초편 6회차 (Generator, Promise, Async/Await) (0) | 2022.04.27 |