[Vue] Vue.js instance 문법
작성:    
업데이트:
카테고리: Vue
Vue.js의 기본 문법
Vue instance
- 모든 Vue 앱은 Vue 함수로 새 인스턴스를 만드는 것부터 시작
- Vue 인스턴스를 생성할 때는 Options 객체 전달
- 여러 Options들을 사용하여 원하는 동작 구현
- Vue Instance === Vue Component
const app = new Vue({
})
Options/DOM
Vue Instance의 Options 객체에서 DOM을 구성하는 요소들을 살펴보자.
가. el
- Vue 인스턴스에 연결(마운트)할 기존 DOM 요소 필요
- CSS 선택자 문자열 or HTML Element로 작성
- new를 이용한 인스턴스 생성 때만 사용
const app = new Vue({
el: '#app'
})
나. data와 methods
- data : Vue 인스턴스의 데이터 객체, Vue 인스턴스의 상태 데이터 정의
-
methods : Vue 인스턴스에 추가할 메서드
- Vue template에서 interpolation을 통해 접근 가능
- v-bind, v-on과 같은 directive에서도 사용 가능
- Vue 객체 내 다른 함수에서 this 키워드를 통해 접근 가능(this === 해당 vue 인스턴스)
const app = new Vue({
el: '#app',
data: {
message: 'Hello',
},
methods: {
greeting: function () {
console.log('hello')
}
}
})
주의📢 화살표 함수를 메서드 정의에 사용하지 않는다.
⭐ 화살표 함수가 부모 context를 binding하기 때문에 ‘this’가 Vue instance가 아니게 된다.
Template 문법
- 렌더링된 DOM을 기본 Vue 인스턴스의 데이터에 선언적으로 바인딩할 수 있는 HTML 기반 템플릿 구문 사용
- Interpolation
- Directive
가. Text
<span>메시지: {{ msg }}</span>
나. Raw HTML
<span v-html="rawHtml"></span>
다. Attribute
<div v-bind:id="dynamicId"></div>
라. JS 표현식
{{ number + 1 }}
{{ message.split('').reverse().join('') }}
Directive
- v- 접두사가 있는 특수 속성
- 속성 값은 단일 JS 표현식이 됨 (v-for은 예외)
- 표현식의 값이 변경될 때 반응적으로 DOM에 적용하는 역할
전달인자(Arguments)
- :(콜론) 을 통해 전달인자를 받을 수 있음
<a v-bind:href="url">...</a>
<a v-on:click="dosomething">...</a>
수식어(Modifiers)
- .(점) 으로 표시되는 특수 접미사
- directive를 특별한 방법으로 바인딩해야함을 의미
<form v-on:submit.prevent="onSubmit"> ... </form>
가. v-text
- element의 textContent를 업데이트
- 내부적으로 interpolation 문법이 v-text로 컴파일
<p v-text="message"></p>
<p>{{ message }}</p>
위의 두 코드는 같다.
나. v-html
- element의 innerHTML을 업데이트
- XSS 공격에 취약
- 임의로 사용자로부터 입력 받은 내용은 v-html에 절대 사용 금지
<div v-html="myHtml"></div>
...
data: {
myHtml: '<b>Hello</b>'
}
다. v-show
- 조건부 렌더링 중 하나
- 속성값은 boolean type data, true이면 display, false이면 display:none
- 요소는 항상 렌더링, DOM에 있음
- 단순히 element에 display 속성을 toggle
<div id="app">
<p v-show="isTrue">
true
</p>
<p v-show="isFalse">
false
</p>
</div>
라. v-if, v-else-if, v-else
- 조건부 렌더링 중 하나
- directive의 표현식이 false라면 렌더링 자체가 되지 않음
- element 및 포함된 directive는 toggle하는 동안 삭제되고 다시 작성
<div id="app">
<div v-if="myType === 'A'">
A
</div>
<div v-else-if="myType === 'B'">
B
</div>
<div v-else-if="myType === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
</div>
v-show와 v-if
v-show (Expensive initial load, cheap toggle)
- CSS display 속성을 hidden으로 만들어 toggle
- 실제로 렌더링은 되지만 눈에 보이지 않음
- 딱 한 번만 렌더링이 되는 경우 v-if에 비해 상대적으로 높은 렌더링 비용
- 자주 변경되는 요소의 경우 한 번 렌더링된 이후 토글만 하면 되므로 비용 감소
v-if (Cheap initial load, expensive toggle)
- 전달인자가 false인 경우 렌더링 자체가 되지 않으므로 렌더링 비용 낮음
- 자주 변경되는 요소의 경우 매번 다시 렌더링 해야하므로 비용 증가
결론
- 자주 변경될 거라면 v-show, 한 번만 쓸 거라면 v-if를 쓰자.
- v-show는 안 보여도 렌더링, v-if는 안 보이면 렌더링 X
마. v-for
- 원본 데이터를 기반으로 element 또는 템플릿 블록을 여러 번 렌더링
- item in items 구문 사용
- item 위치의 변수를 각 요소에서 사용 가능
-
객체의 경우 key
- v-for 사용 시 반드시 key 속성을 각 요소에 작성
- v-if와 함께 사용하는 경우 v-for가 우선순위가 더 높음
- 단, 되도록 v-if와 v-for은 동시 사용 지양
<body>
<div id="app">
<h2>String</h2>
<div v-for="char in myStr">
{{ char }}
</div>
<h2>Array</h2>
<div v-for="fruit in fruits">
{{ fruit }}
</div>
<div v-for="(fruit, idx) in fruits">
{{ idx }} => {{ fruit }}
</div>
<div v-for="todo in todos" :key="todo.id">
<p>{{ todo.title }} => {{ todo.completed }}</p>
</div>
<h2>Object</h2>
<!-- value, key 순서임에 주의한다. -->
<div v-for="(value, key) in myObj">
{{ key }} => {{ value }}
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
myStr: 'Hello World!',
fruits: ['apple', 'banana', 'coconut'],
todos: [
{ id: 1, title: 'todo1', completed: true},
{ id: 2, title: 'todo2', completed: false},
{ id: 3, title: 'todo3', completed: true},
],
myObj: {
name: 'Smith',
age: 25,
}
}
})
</script>
</body>
바. v-on
- element에 EventListener 연결
- 이벤트 유형은 전달인자로 표시
- 특정 이벤트가 발생했을 때, 주어진 코드 실행
- shorthand
- @
- v-on:click → @click
<body>
<div id="app">
<!-- 메서드 핸들러 -->
<!-- v-on:의 축약 : @ -->
<button v-on:click="alertHello">Button</button>
<button @click="alertHello">Button</button>
<!-- 기본 동작 방지 -->
<!-- @submit.prevent -->
<form action="" @submit.prevent="alertHello">
<button>GoGo</button>
</form>
<!-- 키 별칭을 이용한 키 입력 수식어 -->
<!-- space, enter 등을 keyup 했을 때에만 함수 실행 -->
<input type="text" @keyup.enter="log">
<!-- callback 함수에서의 특수문법 () -->
<!-- 'a'를 인자로 넣어 바로 실행한다. 라는 의미가 아닌, -->
<!-- 실행할 때 1번 인자를 'a'로 넣겠다는 의미 --> ⭐
<input type="text" @keyup.enter="log('a')">
<p>{{ message }}</p>
<button @click="changeMessage">change message</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue',
},
methods: {
alertHello: function () {
alert('hello')
},
log: function (event) {
console.log(event)
},
changeMessage() {
this.message = new Date()
}
}
})
</script>
</body>
사. v-bind
- HTML 요소의 속성에 Vue의 상태 데이터를 값으로 할당
- Object 형태로 사용하면 value가 true인 key가 class 바인딩 값으로 할당
- shorthand
- :(colon)
- v-bind:href => :href
<head>
...
<style>
.active {
color: red;
}
.my-background-color {
background-color: yellow;
}
</style>
</head>
<body>
<!-- v-bind : 기본 속성이라 v-가 안되는 속성들을 v-와 엮어주는 방법 -->
<div id="app">
<!-- 속성 바인딩 -->
<!-- <img v-bind:src="imageSrc" alt=""> -->
<img :src="imageSrc" alt="">
<hr>
<!-- 클래스 바인딩 -->
<!-- isRed가 true일 때만 active 클래스 활성화하겠다. -->
<div :class="{ active: isRed }">
클래스 바인딩
</div>
<hr>
<h3 :class="[activeRed, myBackground]">
hello vue
</h3>
<!-- 스타일 바인딩 -->
<p :style="{ fontSize: 20px }">
this is
</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
fontSize: 16,
altMsg: 'this is image',
imageSrc: 'https://picsum.photos/id/310/200/300',
isRed: true,
activeRed: 'active',
myBackground: 'my-background-color',
}
})
</script>
아. v-model
- HTML form 요소의 값과 data를 양방향 바인딩
- 수식어
- .lazy : input 대신 change 이벤트 이후에 동기화
- .number : 문자열 → 숫자
- .trim : 입력에 대한 trim 진행
<body>
<div id="app">
<h2>Input -> Data 단방향</h2>
<p>{{ msg1 }}</p>
<input type="text" @input="onInputChange">
<hr>
<h2>Input <-> Data 양방향</h2>
<p>{{ msg2 }}</p>
<input type="text" v-model="msg2">
<hr>
췤! <input id="box" type="checkbox" v-model="checked">
<label for="box">{{ checked }}</label>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
msg1: '111',
msg2: '222',
checked: true,
},
methods: {
onInputChange (event) {
this.msg1 = event.target.value
},
},
})
</script>
</body>
Options/Data
computed
- 데이터를 기반으로 하는 계산된 속성
- 함수의 형태로 정의 BUT 함수의 반환값이 바인딩
- computed 구성을 위해 종속된 데이터에 따라 저장(캐싱)
- 종속된 데이터가 변경될 때만 함수 실행
- 어떤 데이터에도 의존하지 않는 computed 속성의 경우 불변
- 반드시 반환값이 있어야 한다.
<script>
const app = new Vue({
el: '#app',
data: {
r: 2,
// area: 2*2*3.14,
// perim: 2*2*3.14,
},
computed: {
area: function () {
return this.r ** 2 * 3.14
},
perim: function () {
return 2 * this.r * 3.14
},
}
// watch: {
// area: function () {
// this.area = this.r * this.r * 3.14
// }
// perim: function () {
// this.perim = 2 * this.r * 3.14
// }
// }
})
</script>
computed와 methods
- computed 속성 대신 methods에 함수를 정의 가능
- 최종 결과에 대해 두 가지 접근 방식은 서로 동일
-
차이점은 computed 속성은 종속 대상을 따라 저장(캐싱)
- computed는 종속된 대상이 변경되지 않는 한 computed에 작성된 함수를 여러 번 호출해도 계산을 다시 하지 않고 계산되어 있던 결과 반환
- ⭐ 요약 : 변경 없이 여러 번 호출 → methods는 매번 함수 실행, computed는 재계산 없이 캐시값 반환
<script>
const app = new Vue({
el: '#app',
data: {
sessionId: '',
message: 'Original'
},
// render될 때마다 함수를 재실행
// -> data를 바꾸는 로직 위주 (setter)
methods: {
reverseMessage () {
return this.message.split('').reverse().join('')
}
},
// (data에 의존하는) 계산된 값
// 종속 대상을 따라 저장(캐싱)된다.
// data를 통해 값을 얻는 경우 사용 (getter)
computed: {
reversedMessage () {
return this.message.split('').reverse().join('')
},
isLoggedIn () {
// sessionId의 변화가 없다면 언제 호출되어도 캐시값 반환
return this.sessionId ? true : false
}
},
})
</script>
watch
- 데이터를 감시
- 데이터에 변화가 일어났을 때 실행되는 함수
const app = new Vue({
el: '#app',
data: {
num: 2,
},
watch: {
num: function () {
console.log(`${this.num}이 변경되었습니다.`)
}
},
})
- this.num(내부 종속 대상)이 바뀌면 num 함수 실행
- react의 useEffect와 같다.
computed와 watch
computed
- 특정 데이터를 직접적으로 사용/가공 → 다른 값으로 만들 때 사용
- 종속 데이터의 원본 값은 바꾸지 않고 새로운 값을 ‘계산’하는 것
- 속성은 계산해야 하는 목표 데이터를 정의하는 방식
- “A 값이 A2로 변하면 이전에 A로부터 계산됐던 B 값을 다시 계산해 B2 값을 만들어 보여준다.”
- 선언형 프로그래밍 방식 → “계산해야 하는 목표 데이터 정의”
watch
- 특정 데이터의 변화 상황에 맞춰 다른 data 등이 바뀌어야 할 때 사용
- 감시할 데이터를 지정, 해당 데이터가 바뀌면 특정 함수 실행
- “A 값이 변하면 B 함수를 실행해 작업한다.”
- 특정 대상이 변경되었을 때 콜백 함수를 실행시키기 위한 트리거
- 명령형 프로그래밍 방식 → “데이터가 바뀌면 특정 함수 실행해!”
filter
- 텍스트 형식화를 적용할 수 있는 필터
- interpolation 혹은 v-bind를 이용할 때 사용 가능
-
JS 표현식의 마지막에 ** **(pipe)와 함께 추가 - chaining 가능
<body>
<div id="app">
<div>{{ numbers }}</div>
<div>{{ numbers | getOddNumbers }}</div>
<div>{{ numbers | getOddNumbers | getUnderTen }}</div>
<div>{{ getOddAndUnderTen }}</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
},
filters: {
getOddNumbers(array) {
return array.filter(num => num % 2)
},
getUnderTen(array) {
return array.filter(num => num < 10)
}
},
computed: {
getOddAndUnderTen() {
return this.numbers.filter(num => num%2 && num<10)
}
}
})
</script>
</body>
댓글남기기