Vue.js 입문

Vue에 대한 몇가지 속성을 빠르게 파악하기 위해 기록을 남겨둔다. 공식적인 문서를 위주로 참고해서 작성할 예정!

예제1

1
2
3
<div id="app">
{{ message }}
</div>
1
2
3
4
5
6
var app = new Vue({
el: '#app', //DOM의 id를 여기서 입력해주고
data: { // DOM안의 템플릿에 key value 형태로 데이터를 뿌려줌
message: '안녕하세요 Vue!'
}
})

문자열을 단순히 뿌려줌.
자 이제 뿌려주는걸 넘어서 바인딩! 해주는걸 보자.

예제2

1
2
3
4
5
<div id="app-2">
<span v-bind:title="message">
내 위에 잠시 마우스를 올리면 동적으로 바인딩 된 title을 볼 수 있습니다!
</span>
</div>
1
2
3
4
5
6
var app2 = new Vue({
el: '#app-2',
data: {
message: '이 페이지는 ' + new Date() + ' 에 로드 되었습니다'
}
})
라고 되어있는 키워드가 바인딩의 핵심인데, ```v-bind``` 속성을 **디렉티브** 라고 함. ```v-``` 접두어는 뷰에서 제공하는 특수 속성임을 나타냄.
1
2
3
4
5
6
7
8
위의 예제는 “이 요소의 ```title``` 속성을 Vue 인스턴스의 message 속성으로 최신 상태를 유지 합니다.” 를 의미함


#### 조건문과 반복문
```html
<div id="app-3">
<p v-if="seen">이제 나를 볼 수 있어요</p>
</div>
1
2
3
4
5
6
var app3 = new Vue({
el: '#app-3',
data: {
seen: true
}
})

v-if 라는 속성을 통해 data의 seen 속성이 true면 DOM을 그려줌. 텍스트 속성뿐 아니라 DOM의 구조에서도 데이터를 바인딩 할 수 있다는 뜻임.

1
2
3
4
5
6
7
<div id="app-4">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</div>
1
2
3
4
5
6
7
8
9
10
var app4 = new Vue({
el: '#app-4',
data: {
todos: [
{ text: 'JavaScript 배우기' },
{ text: 'Vue 배우기' },
{ text: '무언가 멋진 것을 만들기' }
]
}
})

이제 위와 같은 예제를 통해서 알 수 있는건, v-키워드가 들어간 이후의 내용은 data 에 등장하는 변수라고 생각하면 된다는 것이다. 비록 “”을 통해 문자열처럼 나타내지만 data내의 key, value로 존재하는 변수 나타낸다.

사용자 입력 핸들링

사용자가 앱과 상호 작용할 수 있게 하기 위해 우리는 v-on 디렉티브를 사용하여 Vue 인스턴스에 메소드를 호출하는 이벤트 리스너를 첨부 할 수 있음

1
2
3
4
<div id="app-5">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">메시지 뒤집기</button>
</div>
1
2
3
4
5
6
7
8
9
10
11
var app5 = new Vue({
el: '#app-5',
data: {
message: '안녕하세요! Vue.js!'
},
methods: { // 이게 추가됨
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})

el, data와 같은 레벨에서 methods가 추가 된 것을 확인 할 수 있음. Vue 인스턴스 내의 데이터에 접근할 땐 this 키워드를 사용함.

양방향 바인딩

디렉티브를 통해서 양방향으로 바인딩 할 수 있게 한다고함. 이게 아니면 아마.. 위에 처럼 event listenr (```v-on```)를 써서 작업해야하지 않을까?
1
2
3
4
5
```html
<div id="app-6">
<p>{{ message }}</p>
<input v-model="message">
</div>
1
2
3
4
5
6
var app6 = new Vue({
el: '#app-6',
data: {
message: '안녕하세요 Vue!'
}
})

컴포넌트를 사용한 작성방법

UI는 반복적인 부분이 매우 많음. 컴포넌트에 대해서 생각하게 되는건 당연한 수순. 컴포넌트는 대략 “트리” 구조와 비슷함. 구조안에 구조가 있다고 보면 될듯. 컴포넌트는 사실 DOM쪽에 가깝고, 로직은 뷰 앱단에서 처리해야한다고 봄.

컴포넌트 등록 방법!

1
2
3
4
// todo-item 이름을 가진 컴포넌트를 정의합니다
Vue.component('todo-item', {
template: '<li>할일 항목 하나입니다.</li>'
})
1
2
3
4
<ol>
<!-- todo-item 컴포넌트의 인스턴스 만들기 -->
<todo-item></todo-item>
</ol>

위의 예제는 모든 할일이 똑같은 컴포넌트를 찍어낸거나 다름없음. 이는 뭔가 부족함.. 실제 앱은 다양한 입력을 대처해야하니까. 이를 위해서 ```prop`` 옵션이 나오는 것도 당연한 수순.

  1. 컴포넌트 정의하고~ 거기에 todo 라는 prop 옵션을 넣어준다.

  2. 컴포넌트에 대한 Vue app을 로직을 정의 한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /// DOM 쪽에 가까움
    Vue.component('todo-item', {
    // 이제 todo-item 컴포넌트는 "prop" 이라고 하는
    // 사용자 정의 속성 같은 것을 입력받을 수 있습니다.
    // 이 prop은 todo라는 이름으로 정의했습니다.
    props: ['todo'],
    template: '<li>{{ todo.text }}</li>'
    })

    /// 로직 쪽에 가까움
    var app7 = new Vue({
    el: '#app-7',
    data: {
    groceryList: [
    { id: 0, text: 'Vegetables' },
    { id: 1, text: 'Cheese' },
    { id: 2, text: 'Whatever else humans are supposed to eat' }
    ]
    }
    })
  3. DOM에서 컴포넌트를 생성해주고, todo prop에 Vue app의 변수들을 바인딩해서 넣어준다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <div id="app-7">
    <ol>
    <!--
    이제 각 todo-item 에 todo 객체를 제공합니다.
    화면에 나오므로, 각 항목의 컨텐츠는 동적으로 바뀔 수 있습니다.
    또한 각 구성 요소에 "키"를 제공해야합니다 (나중에 설명 됨).
    -->
    <todo-item
    v-for="item in groceryList"
    v-bind:todo="item"
    v-bind:key="item.id">
    </todo-item>
    </ol>
    </div>

Vue 인스턴스 생성

(약간 복잡함~! 마음의 준비를 하자)
Vue 인스턴스를 인스턴스화 할 때는 데이터, 템플릿, 마운트할 엘리먼트, 메소드, 라이프사이클 콜백 등의 옵션을 포함 할 수있는 options 객체를 전달 해야함

각 Vue 인스턴스는 data 객체에 있는 모든 속성을 프록시 처리 함 (프록시 처리??)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 데이터 객체
var data = { a: 1 }

// Vue인스턴스에 데이터 객체를 추가합니다.
var vm = new Vue({
data: data
})

// 같은 객체를 참조합니다!
vm.a === data.a // => true

// 속성 설정은 원본 데이터에도 영향을 미칩니다.
vm.a = 2
data.a // => 2

// ... 당연하게도
data.a = 3
vm.a // => 3

데이터가 변경되면 화면은 다시 렌더링됨. 유념할 점은, data에 있는 속성들은 인스턴스가 생성될 때 존재한 것들만 반응형이라는 것. 즉, 다음과 같이 새 속성을 추가하면:

1
vm.b = 'hi'

b가 변경되어도 화면이 갱신되지 않음. 어떤 속성이 나중에 필요하다는 것을 알고 있으며, 빈 값이거나 존재하지 않은 상태로 시작한다면 아래와 같이 초기값을 지정할 필요가 있음. (여기에서 유일한 예외는 Object.freeze()를 사용하는 경우)

1
2
3
4
5
6
7
data: {
newTodoText: '',
visitCount: 0,
hideCompletedTodos: false,
todos: [],
error: null
}

인스턴스 라이프사이클 훅

각 Vue 인스턴스는 데이터 관찰을 설정하고, 템플릿을 컴파일하고, 인스턴스를 DOM에 마운트하고, 데이터가 변경 될 때 DOM을 업데이트해야 할 때 일련의 초기화 단계!!! 를 거침.
그 과정에서 사용자 정의 로직을 실행할 수있는 라이프사이클 훅 도 호출됨. 예를 들어, created 훅은 인스턴스가 생성된 후에 호출됨. 예:

1
2
3
4
5
6
7
8
9
10
new Vue({
data: {
a: 1
},
created: function () {
// `this` 는 vm 인스턴스를 가리킵니다.
console.log('a is: ' + this.a)
}
})
// => "a is: 1"

인스턴스 라이프사이클의 여러 단계에서 호출될 다른 훅도 있음. 그 예로 mounted, updateddestroyed가 있음. 모든 라이프사이클 훅은 this 컨텍스트가 호출하는 Vue 인스턴스를 가리키며 호출됨. Vue 세계에서 “컨트롤러”의 컨셉이 어디에 있는지 궁금할 수 있음. 답은 컨트롤러가 없다! 컴포넌트의 사용자 지정 로직은 이러한 라이프사이클 훅으로 분할됨.

Life cycle Diagram of Vue
lifecycle{: height=”50%” width=”50%”}


템플릿 문법

여러가지 문법들이 있지만, 지금 당장에 필요한 것 위주로 일단 기록해둔다.

약어

v- 접두사는 템플릿의 Vue 특정 속성을 식별하기 위한 시각적인 신호 역할을 함. 이 기능은 Vue.js를 사용하여 기존의 마크업에 동적인 동작을 적용할 때 유용하지만 일부 자주 사용되는 디렉티브에 대해 너무 장황하다고 느껴질 수 있음. 동시에 Vue.js가 모든 템플릿을 관리하는 SPA를 만들 때 v- 접두어의 필요성이 떨어짐. 따라서 가장 자주 사용되는 두개의 디렉티브인 v-bind와 v-on에 대해 특별한 약어를 제공.

v-bind 약어
1
2
3
4
5
<!-- 전체 문법 -->
<a v-bind:href="url"> ... </a>

<!-- 약어 -->
<a :href="url"> ... </a>
v-on 약어
1
2
3
4
5
<!-- 전체 문법 -->
<a v-on:click="doSomething"> ... </a>

<!-- 약어 -->
<a @click="doSomething"> ... </a>

이들은 일반적인 HTML과 조금 다르게 보일 수 있음. 하지만 :와 @는 속성 이름에 유효한 문자이며 Vue.js를 지원하는 모든 브라우저는 올바르게 구문 분석을 할 수 있음. 또한 최종 렌더링 된 마크업에는 나타나지 않음. 약어는 완전히 선택사항이지만 나중에 익숙해지면 편할 것

계산된 속성(Computed prop)

템플릿 내에서 사용하는 표현식은 매우 편리하지만 단순한 연산에만 사용해야 함. 너무 많은 로직을 템플릿에 넣으면 유지보수가 어려움!

1
2
3
<div id="example">
{{ message.split('').reverse().join('') }}
</div>

이 시점에서, 템플릿은 더이상 간단하지 않고 장황함(가정). 이 때문에 복잡한 로직의 경우, 반드시 계산된 속성 을 사용해야함.
계산된 속성을 사용한 경우,

기본예제1

1
2
3
4
<div id="example">
<p>원본 메시지: "{{ message }}"</p>
<p>뒤집히도록 계산된 메시지: "{{ reversedMessage }}"</p>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
var vm = new Vue({
el: '#example',
data: {
message: '안녕하세요'
},
computed: {
// 계산된 getter
reversedMessage: function () {
// `this` 는 vm 인스턴스를 가리킵니다.
return this.message.split('').reverse().join('')
}
}
})

여기서 우리는 계산된 속성인 reversedMessage를 선언했음. 우리가 제공하는 함수는 vm.reversedMessage속성에 대한 getter 함수(따로 셋팅은 안해줘도 얻어오는)로 사용 됨.

1
2
3
console.log(vm.reversedMessage) // => '요세하녕안'
vm.message = 'Goodbye'
console.log(vm.reversedMessage) // => 'eybdooG'

vm.reversedMessage의 값은 항상 vm.message의 값에 의존함.

일반 속성처럼 템플릿의 계산된 속성에 데이터 바인딩 할 수 있음. Vue는 vm.reversedMessagevm.message에 의존하는 것을 알고 있기 때문에 vm.message가 바뀔 때 vm.reversedMessage에 의존하는 바인딩을 모두 업데이트할 것. 그리고 가장 중요한 것은 우리가 선언적으로 의존 관계를 만들었다는 것. 계산된 getter 함수는 사이드 이펙트가 없어 테스트와 추론하기에 쉬워짐.

1

1

1

1

Author

Joosung Yoon

Posted on

2018-04-20

Updated on

2022-08-28

Licensed under

댓글