HTML, CSS 등의 마크업 속성과 뷰 인스턴스에서 정의한 데이터 및 로직들을 연결하여 사용자가 브라우저에서 볼 수 있는 형태의 HTML로 변환해주는 속성이다.
<script>
new Vue({
template : '<p> Hello {{ message }} </p>'
});
</script>
위와 같이 template 속성에서 정의한 마크업과 데이터는 가상 dom 기반의 render() 함수로 변환되고, 변환된 함수는 최종적으로 사용자가 볼 수 있게 화면을 그리는 역할을 한다.
이외에도 ES6 싱글 파일 컴포넌트 체계의 <template>
를 활용하는 방법도 있지만 우선 넘어가도록 한다.
아무튼 템플릿에서 사용하는 뷰의 속성의 종류는 아래와 같다.
HTML 화면 요소를 뷰 인스턴스의 데이터와 연결하는 것을 의미함
{{ }}
<div id="app"> <!-- <div id="app" v-once> -->
{{ message }}
</div>
<script>
new Vue({
el: '#app',
data : {
message : 'Hello Vue.js!'
}
});
</script>
v-bind
속성 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue v-bind example</title>
</head>
<body>
<div id="app">
<p v-bind:id="idA">아이디 바인딩</p> <!-- v-bind:는 :로 간소화 할 수 있다. -->
<p v-bind:class="classA">클래스 바인딩</p> <!-- ex) :class="classA" -->
<p v-bind:style="styleA">스타일 바인딩</p> <!-- ex) :style="styleA" -->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data : {
idA: 10,
classA: 'container',
styleA: 'color: blue'
}
});
</script>
</body>
</html>
뷰 템플릿에서도 자바스크립트 표현식을 아래와 같이 사용할 수 있다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue JS example</title>
</head>
<body>
<div id="app">
<div v-bind:id="app">
<p>{{ message }}</p>
<p>{{ message + "!!!!" }}</p>
<p>{{ message.split('').reverse().join('') }}</p> <!-- 자바스크립트 내장 API 사용 가능 -->
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data : {
message: 'Hello Vue.js!'
}
});
</script>
</body>
</html>
하지만 사용에서 주의점도 존재한다. 크게 두가지로 아래와 같다.
첫째, 자바스크립트의 선언문과 분기 구문은 사용할 수 없다.
둘째, 복잡한 연산은 인스턴스 안에서 처리하고 화면에는 간단한 연산 결과만 표시해야 한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue JS example</title>
</head>
<body>
<div id="app">
<!-- 코드 실행 시, (x) 항목은 주석처리 후 실행해야 됨 -->
{{ var a = 10; }} <!-- (x) 선언문은 사용 불가능 -->
{{ if(true) {return 100} }} <!-- (x) 분기 구문은 사용 불가능 -->
{{ true ? 100 : 0 }} <!-- (o) 삼항 연산자는 사용 가능 -->
{{ message.split('').reverse().join('') }} <!-- (x) 복잡한 연산은 인스턴스 안에서 수행 -->
{{ reversedMessage }} <!-- (o) 스크립트 computed 속성으로 계산 후 최종 값만 표현 -->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data : {
message: 'Hello Vue.js!'
},
computed: { // 데이터 속성을 자동으로 계산해주는 속성
reversedMessage : function() {
return this.message.split('').reverse().join('');
}
}
});
</script>
</body>
</html>
위 코드를 실행하면 아래의 복잡한 연산부분들은 감이 올 것이다. 사실 복잡한 연산을 인스턴스에서 수행한다고 해서 별도 오류가 생기진 않는다. 하지만, computed 속성을 수행하면 코드의 가독성을 높이는 것 뿐만 아니라, computed 속성의 캐싱 효과를 얻을 수 있다. 여기서 말하는 캐싱효과란, 반복적인 연산에 대해 미리 계산 후 저장하여, 필요할 때 바로 불러오는 것으로 이에 대한 효과는 뒤에서 자세히 살펴본다.
뷰 디렉티브(Directive)란 HTML 태그 안에 v-접두사를 가지는 모든 속성을 의미한다. 즉, 화면의 요소를 더 쉽게 조작하기 위해 사용하는 기능으로, 뷰 데이터 값이 변경되었을 때, 화면의 요소들이 Reactive하게 반응하여 변경된 데이터 값에 따라 갱신된다.
<a v-if="flag">두잇 Vue.js</a>
위 코드의 <a>
는 뷰 인스턴스 데이터 속성에 정의된 flag 값이 참(true)이면 보일 것이고, 거짓(false)이면 보이지 않을 것이다.
디렉티브 이름 | 역할 |
---|---|
v-if | 지정한 뷰 데이터 값의 참/거짓 여부에 따라 해당 HTML 태그를 화면에 표시하거나 표시하지 않음 |
v-for | 지정한 뷰 데이터의 개수만큼 HTML 태그를 반복 출력함 |
v-show | v-if와 유사하게 데이터 진위 여부에 따라 HTML 태그를 화면에 표시하거나 하지 않음. 다만 v-show는 css 효과에 한함 |
v-bind | HTML 태그의 기본 속성과 뷰 데이터 속성을 연결함 |
v-on | 화면 요소의 이벤트를 감지하여 처리할 때 사용함 |
v-model | 폼(form)에 주로 사용되며, 폼에 입력한 값을 뷰 인스턴스의 데이터와 즉시 동기화 함. 화면에 입력된 값을 저장하여 서버에 보내거나, watch와 같은 고급 속성을 이용하여 추가 로직을 수행할 수 있음. <input> , <select> , <textarea> 태그에만 사용할 수 있음 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue Template - Directives </title>
</head>
<body>
<div id="app">
<a v-if="flag">두잇 Vue.js</a>
<ul>
<li v-for="system in systems">{{ system }}</li>
</ul>
<p v-show="flag">두잇 Vue.js</p>
<h5 v-bind:id="uid">뷰 입문서</h5> <!-- <h5 id=10>로 화면에 표시됨 -->
<button v-on:click="popupAlert">경고 창 버튼</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data : {
flag: true,
systems: ['android', 'ios', 'window'],
uid: 10
},
methods: {
popupAlert: function() {
return alert('경고 창 표시');
}
}
});
</script>
</body>
</html>
뷰에서는 화면에서 발생한 이벤트를 처리하기 위해 v-on 디렉티브와 methods 속성을 활용한다. 사실 해당 내용은 바로 이전에 수행했던 디렉티브 예시로도 이해가 충분히 되리라 생각한다.
또한 v-on 디렉티브로 method 호출 시, 인자 값을 넘길 수도 있으며, 인자 값을 전달하지 않아도 event 인자를 정의하면 해당 돔 요소의 이벤트 객체에도 접근할 수 있다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue example 05-7 </title>
</head>
<body>
<div id="app">
<button v-on:click="clickBtn">경고 창 버튼</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
methods: {
clickBtn :function(event) {
console.log(event);
}
}
});
</script>
</body>
</html>
데이터의 연산들을 정의하는 영역
이전에 복잡한 데이터 연산은 HTML영역이 아닌 computed속성에서 해야 가독성과 캐싱, 두 마리의 토끼를 잡을 수 있다고 설명했었다.
데이터 변화를 감지하여 자동으로 특정 로직을 수행하는 영역
데이터 호출과 같이 시간이 상대적으로 더 많이 소모되는 비동기 처리에 적합하다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue watch example</title>
</head>
<body>
<div id="app">
<input v-model="message">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js'
},
watch: {
message: function(data) {
console.log("message의 값이 바귑니다 : ", data);
}
}
});
</script>
</body>
</html>
위 코드와 같이, <input>
박스 입력 값을 v-model 디렉티브로 연결하여, 입력 값의 변화가 있을 때마다 watch 속성에서 변화된 로그 값을 출력하게 된다.
지금까지 HTML 파일로 예시를 들었다. 사실 HTML 내부에서는 구문 강조가 별도로 되지 않기 때문에 태그의 관계나 스타일 적용에 어려움을 겪을 수 있다.
게다가 HTML로 작성을 하다보면, Vue를 Vue 답게 사용할 수 없다. Vue Application은 여러 개의 컴포넌트로 화면을 구성하고, 페이지 사이를 이용할 때는 라우터를 사용해야 한다.
.vue 파일로 프로젝트 구조를 구성하는 방식
따라서 Vue Application에서는 싱글 파일 컴포넌트(Single File Components)체계를 활용한다. .vue
파일은 아래와 같은 구조를 갖는다.
1. 화면에 표시할 요소들을 정의하는 영역(HTML, Vue데이터 바인딩, ...)
<template>
</template>
2. Vue 컴포넌트 내용을 정의하는 영역(template, data, methods, ...)
<script>
</script>
3. 템플릿에 추가한 HTML 태그의 CSS 스타일을 정의하는 영역
<style>
<style>
앞에서 배운 싱글 파일 컴포넌트 체계를 사용하기 위해서는 .vue 파일을 웹 브라우저가 인식할 수 있는 형태의 파일로 변환해주는 웹팩(Webpack)이나 브라우저리파이(Browserify)와 같은 도구가 필요하다.
웹팩(Webapck)이란, 웹 앱의 자원(HTML, CSS, IMG)들을 자바스크립트 모듈로 변환해 하나로 묶어 웹 성능을 향상시켜주는 자바스크립트 모듈 번들러이다.
하지만 아무튼 이런 도구들을 하나하나 배우긴 어려우니, 우리는 CLI(Command Line Interface)를 사용하자.
$ npm install vue-cli -global
뷰 개발을 시작할 때, 초기 프로젝트를 쉽게 구성해주는 명령어는 $ vue init
이다. 이를 입력할 때 사용하는 프로젝트 템플릿 종류는 다음과 같이 6가지다.
템플릿 종류 | 설명 |
---|---|
$ vue init webpack | 고급 웹팩 기능 (테스팅, 문법 검사 등 지원) |
$ vue init webpack-simple | 웹팩 최소 기능 (빠른 화면 프로타이핑용) |
$ vue init browserify | 고급 브라우저리파이 기능 (테스팅, 문법 검사 등 지원) |
$ vue init browserify-simple | 브라우저리파이 최소 기능(빠른 화면 프로타이핑용) |
$ vue init simple | 최소 뷰 기능만 들어간 HTML 파일 1개 생성 |
$ vue init pwa | 웹팩 기반의 프로그레시브 웹 앱 |
$ vue init webpack-simple
$ npm install
위 명령어를 실행하면 vue application을 구동하기 위한 라이브러리를 모두 다운로드하게 된다. 다운로드가 완료되면 아래와 같은 폴더 구조가 생성된다.
(1) node_modules : $ npm insatll
로 다운받은 라이브러리가 존재하는 위치
(2) src : .vue
파일을 비롯하여 vue app이 동작하는데 필요한 로직이 들어갈 위치
(3) index.html : 뷰로 만든 웹앱의 시작점. $ npm run dev
실행 시 로딩되는 파일
(4) package.json : npm 설정 파일. vue app이 동작하는데 필요한 라이브러리들을 정의하는 파일
(5) webpack.config.js : 웹팩 설정파일. 웹팩 빌드를 위해 필요한 로직들을 정의하는 파일
특히 (4) package.json
파일 내용은 아래와 같다.
{
//프로젝트 정보
"name": "cli-template",
"description": "A vue.js project",
"version": "1.0.0",
"author": "hailey",
"license": "MIT",
"private": true,
//npm 실행 명령어
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
},
//뷰, 웹팩 관련 라이브러리
"dependencies": {
"vue": "^2.5.11"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
],
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.0",
"babel-preset-stage-3": "^6.24.1",
"cross-env": "^5.0.5",
"css-loader": "^0.28.7",
"file-loader": "^1.1.4",
"vue-loader": "^13.0.5",
"vue-template-compiler": "^2.4.4",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.1"
}
}
$ vue init
명령어 실행 시에 생성되는 파일로, 프로젝트 정보를 담고 있는 설정 파일임과 동시에 npm 명령어 및 뷰로 app을 제작하는데 필요한 라이브러리 정보를 포함하고 있다.
마지막으로 $ npm run dev
를 실행하면 브라우저가 실행되게 된다. 이는 index.html 파일이 보여지게 되는 것이다.
특히 아래 로그를 보면, http://localhos:8080
에서 구동되고 있으며, 웹팩 결과값이 /dist/
에서 제공되고 있다는 것을 확인할 수 있다.
웹팩에서 지원하는 라이브러리로 싱글 파일 컴포넌트 체계에서 사용하는 .vue 파일의 내용을 브라우저에서 실행 가능한 웹 페이지의 형태로 변환해준다.
앞선 예에서 simpleProject를 실행했을 때, App.vue
파일의 내용이 웹페이지에 표시되는 것을 확인했다. 우리가 $ npm run dev
실행 시 App.vue에서 <template>
, <script>
, <style>
의 내용이 각 HTML, JS, CSS 코드로 인식될 수 있도록 뷰 로더가 변환 작업이 수행된다.
webpack.config.js
파일을 보면 다음과 같이 뷰 로더가 적용되어 있다.
module: {
rules: [
{
test: /\.css$/, //대상파일
use: [ //사용로더
'vue-style-loader',
'css-loader'
],
},
컴포넌트는 체계적인 프로젝트 폴더 구조를 위해 일반적인 방식에 맞춰, /app/components
밑에 생성한다면, 그 각각의 컴포넌츠 내 모든 .vue
파일에 뷰 로더가 적용될 것이다.