/ #JAVASCRIPT#VUE.JS

Vue.js: Instance 생성

Vue란?

Vue.js는 웹 어플리케이션을 개발하기위한 프로그레시브 자바스크립트 프레임워크입니다. MVVM(Model-View-ViewModel) 패턴을 사용하지만, 코어 라이브러리는 ViewModel에 집중되어 있습니다.

주로 ECMAScript 6(ES6) 문법을 사용하는 React.js와 달리 웹컴포넌트(WebComponent)를 기반으로 하는 컴포넌트 개발 방식을 지원하기때문에 다른 프레임워크로 제작된 웹 애플리케이션 프로젝트에 Vue 컴포넌트를 점진적으로 통합시킬 수 있다는 장점이 있습니다.

Vue는 Google Creative Laps에서 근무하던 중국 출신의 에반 유(Evan You)에 의해 개발되었습니다. 에반 유는 구글의 Angular.js를 이용한 프로젝트를 진행하면서 Angular.js의 양방향 데이터 바이딩에 매료되었고, 해당 기능을 가지면서 조금 더 가벼운 프레임워크를 만들고자 했습니다. 조금씩 자신의 프로젝트에 자신이 만든 경량화 라이브러리를 적용하였고, 2013년에 이르러 해당 라이브러리를 Vue.js라고 명명했습니다. 2014년 Hacker News 등을 통해 세상에 공개된 이후 개발자들의 뜨거운 관심을 받아 최근에는 React.js에 이어 2번째로 대중적인 자바스크립트 프레임워크가 되었습니다.

프론트엔드 개발의 대규모화 추세에 따라 2020년 Vue 3.0 One Piece가 공개되었지만, 여기서는 2.7 Naruto 버전을 기준으로 예제를 작성하도록 하겠습니다.

MVVM 패턴

Vue는 MVVM 패턴을 사용하며, 코어의 경우 ViewModel 레이어에 해당하는 라이브러리 입니다.

img001

MVVM 패턴은 모델(Model), 뷰(View), 뷰모델(ViewModel)로 구성된 디자인 패턴입니다.

사용자의 입력(Input)이 컨트롤러(Controller)로 전달되는 MVC 패턴과 달리 MVP 패턴과 같이 모든 사용자의 입력은 뷰(View)로 전달됩니다.

View와 Presenter의 의존성이 강한 MVP 패턴과 달리 MVVM 패턴은 View와 ViewModel 사이의 의존성도 고려하여 각 구성요소를 독립적으로 작성할 수 있습니다. View와 ViewModel은 커맨드 패턴 또는 데이터 바인딩을 통해 통신함으로써 의존성을 제거할 수 있게 됩니다.

ViewModel

뷰모델(ViewModel)은 Model과 View를 동기화시키는 객체입니다. Vue.js에서 모든 Vue 인스턴스(Instance)는 뷰모델에 해당합니다.

Vue 인스턴스는 아래와 같이 생성할 수 있습니다.

Vue 인스턴스 생성
new Vue();

View

뷰(View)는 Vue 인스턴스에 의해 관리되는 DOM 입니다.

ViewModel은 HTML을 기반으로 하는 템플릿(Template) 구문을 통해 선언적으로 렌더링된 DOM에 데이터를 바인딩 할 수 있으며, $el라는 내부 프로퍼티를 통해 View를 관리할 수 있습니다.

View binding
<!DOCTYPE html>
<html lang="en">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
<script>
  const vm = new Vue({el: '#app'});
</script>
</body>
</html>

img002

Model

모델(Model)은 일반적인 자바스크립트 객체입니다.

img003

모델이 Vue 인스턴스의 data로 사용되면 내부적으로 모델 속성이 getter와 setter로 전환되며, 해당 로직을 통해 데이터의 변경이나 접근을 감지하는 observe 기능이 활성화됩니다. 즉, 데이터가 변경되면 notify 기능을 통해 해당 데이터를 바인딩(binding)한 뷰(View)를 찾아 update 함으로써 뷰와 모델을 동기화시킬 수 있습니다. 더티 체크가 필요하지 않으며, 뷰를 업데이트하기 위한 명시적인 신호를 보낼 필요도 없습니다.

모델(Model) 선언
const model = {
    message: 'hello'
}
const vm = new Vue({
    data: model
});

ViewModel에서 $data 프로퍼티를 통해 모델에 접근 가능하며, ViewModel은 관찰하는 모델의 모든 속성을 프록시(proxy) 하고 있으므로 viewModel을 통해 모델에 접근해도 동일한 데이터에 접근할 수 있습니다.

img004

콘솔창을 통해 위와 같이 확인하면 vm.$data.message와 vm.message가 동일한 데이터를 참조한다는 사실을 알 수 있습니다.

Vue 인스턴스 생성

Vue는 주로 node.js 환경에서 vue-cli을 통해 개발하지만 cdn을 통해 모듈 형식으로 개발할 수도 있습니다. 이번 글에서는 후자를 통해 개발하겠습니다.

워크스페이스(work space)에 vue 폴더를 만들고 해당 폴더에 index.html 파일을 생성한 후 다음 코드를 작성합니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>

이제 main.js 파일을 만들어서 Vue 인스턴스를 생성하고, id가 app인 element에 연결하도록 하겠습니다.

다음 코드와 같이 el 옵션에 css 선택자를 value로 입력하면 됩니다.

main.js
const mv = new Vue({
  el: '#app'
})

index.html 파일을 열고 콘솔창에 mv를 입력하면 Vue 인스턴스가 생성되어 있습니다.

img005

연결된 element의 DOM에 접근하고 싶다면 $el 프로퍼티를 참조합니다.

img006

Vue 인스턴스의 $mount 메소드를 통해서 동적으로 element에 연결할 수도 있습니다.

main.js
const mv = new Vue();
mv.$mount('#app');

데이터 바인딩

data 옵션

data 옵션은 Vue 인스턴스가 관리하는 데이터 즉, Model을 설정합니다. Vue 인스턴스가 생성될 때 설정된 Model의 속성은 ViewModel에 의해 관리되며, 속성이 변경되면 ViewModel이 이를 감지하여 해당 속성이 바인딩된 View를 업데이트합니다.

data 옵션은 다음과 같이 JSON 타입으로 줄 수 있습니다.

main.js
const mv = new Vue({
  data: {
    message: 'Hello, world!'
  }
}).$mount('#app')

JSON 타입을 리턴하는 함수로 작성할 수도 있습니다.

main.js
const mv = new Vue({
  data() {
    return {
      message: 'Hello, world!'
    }
  }
}).$mount('#app')

다음에 설명할 Component의 경우 하나의 코드를 재사용하게 되는데, 이때 JSON 타입으로 data를 설정한다면 동일한 컴포넌트를 사용하는 Vue 인스턴스에서는 동일한 Model 데이터를 공유하게 되어 의도하지 않은 결과가 나올 수 있습니다. 함수형태로 작성한다면 참조값을 반환하는 것이 아니라 새로운 데이터 객체를 생성하여 반환하므로 서로 다른 모델 데이터를 가질 수 있게 됩니다.

텍스트 보간

Vue 인스턴스에 선언된 데이터를 View에 바인딩(binding)하기 위해서는 보간법을 사용합니다. 기본적으로 Mustache 구문을 사용하여 데이터를 바인딩합니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app"> {{ message }} </div>
</body>
</html>

img007

delimiters 옵션을 설정하면 {{ ... }} 기호 대신에 사용자가 정의한 기호를 설정할 수도 있습니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app">[[ message ]]</div>
</body>
</html>
main.js
const mv = new Vue({
  delimiters: ['[[', ']]'],
  data: {
    message: 'Hello, world!'
  }
}).$mount('#app')

디렉티브(directive)를 통해 데이터를 바인딩 할 수도 있습니다. 디렉티브는 HTML 템플릿 구문에서 v- 접두사가 붙은 속성을 말하며, 텍스트 보간에 대해서는 v-text 속성을 사용합니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app" v-text="message"></div>
</body>
</html>

View에 바인딩된 모델 속성을 변경하면 ViewModel이 이를 감지하여 View를 업데이트시킵니다.

콘솔창에 mv.message = 'wellcome!'이라고 입력하면 View가 업데이트 되는 것을 확인할 수 있습니다.

img008