티스토리 뷰

JavaScript/Vue.js

[Vue.js] 뷰 템플릿

nc2u 2019. 1. 13. 04:05


뷰 템플릿이란?

뷰의 템플릿(Template)은 HTML, CSS 등의 마크업 속성과 뷰 인스턴스에서 정의한 데이터 및 로직들을 연결하여 사용자가 브라우저에서 볼 수 있는 형태의 HTML로 변환해 주는 속성이다.

템플릿 속성을 사용하는 방법은 두 가지로, 첫 번째는 ES5에서 뷰 인스턴스의 template 속성을 활용하는 방법이다. 예를 들어 template: <p>Hello {{ message }}</p>와 같은 코드가 템플릿을 의미한다.

<!-- ES5에서 template 속성 -->
<script>
    new Vue({
        template: '<p>Hello {{ message }}</p>'
    });
</script>

여기서 템플릿 속성에 대해 한 가지 알아 둘 특징이 있다. 사용자가 볼 수는 없지만 라이브러리 내부적으로 template 속성에서 정의한 마크업 + 뷰 데이터를 가상 돔 기반의 render()함수로 변환한다.

두 번째는 싱글 파일 컴포넌트 체계의 <template>코드를 활용하는 방법이다.

<!-- ES6 : 싱글 파일 컴포넌트 체계 -->
<template>
    <p>Hello {{ message }}</p>
</template>

템플릿에서 사용하는 뷰의 속성과 문법은 다음과 같은 것들이 있다.


  • 데이터 바인딩
  • 자바스크립트 표현식
  • 디렉티브
  • 이벤트 처리
  • 고급 템플릿 기법

데이터 바인딩

데이터 바인딩(Data Binding)은 HTML 화면 요소를 뷰 인스턴스이 데이터와 연결하는 것을 의미한다. 주요 문법으로는 {{ }}문법과 v-bind속성이 있다.


{{ }} – 콧수염 괄호

{{ }}는 뷰 인스턴스이 데이터를 HTML 태그에 연결하는 가장 기본적인 텍스트 삽입 방식인데 모양이 콧수염과 비슷하다고 하여 콧수염 괄호라고 부른다. 뷰 뿐만 아니라 다른 언어나 프레임워크에서도 자주 사용되는 템플릿 문법(template syntax)이다. 간단히 형식을 정리하면 다음과 같다.

<!-- {{ }}를 이용한 데이터 바인딩 -->
<div id="app">
    {{ message }}
</div>

<script>
    new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue.js!'
        }
    });
</script>

위 코드는 data 속성의 message 속성 값인 Hello Vue.js!<div>태그 안의 {{ message }}에 연결하여 화면에 나타내는 코드이다. 여기서 만약 data 속성의 message 값이 바뀌면 뷰 반응성에 의해 화면이 자동으로 갱신된다.

만약 뷰 데이터가 변경되어도 값을 바꾸고 싶지 않다면 아래와 같이 v-once 속성을 사용한다.

<!-- v-once 속성을 이용한 1회 바인딩 -->
<div id="app" v-once>
    {{ message }}
</div>

v-bind

v-bind는 아이디, 클래스, 스타일 등의 HTML 속성(attributes) 값에 뷰 데이터 값을 연결할 때 사용하는 데이터 연결방식이다. 형식은 v-bind 속성으로 지정할 HTML 속성이나 props 속성 앞에 접두사로 붙여준다.

<!-- v-bind 예제 -->
...
<div id="app">
    <p v-bind:id="idA">아이디 바인딩</p>
    <p v-bind:class="classA">클래스 바인딩</p>
    <p v-bind:style="styleA">스타일 바인딩</p>
</div>
...
<script>
    new Vue({
        el: '#app',
        data: {
            idA: 10,
            classA: 'container',
            styleA: 'color: blue'
        }
    });
</script>

위 코드는 HTML의 기본 속성인 id, class, style의 앞에 v-bind:를 붙여서 뷰 인스턴스에 정의한 데이터 속성과 연결하여 화면에 나타내는 예제이다. 이 코드를 실행하면 data 속성의 idA, classA, styleA 값이 화면의 요소에 각각 연결되어 나타난다.

추가로 v-bind:문법을 :로 간소화할 수 있다. 예를 들어, v-bind:id와 :id는 같은 동작을 한다. 다만 약식보다는 v-bind: 속성을 이용하는 것이 HTML문법과 구분하거나 코드를 파악하기 쉽다.


자바스크립트 표현식

뷰의 템플릿에서도 자바스크립트 표현식을 쓸 수 있다. 데이터 바인딩 방법 중 하나인 {{ }} 안에 자바스크립트 표현식을 넣으면 된다. 다음 예제들은 message 값을 화면에 나타낼 때 간단한 자바스크립트 연산을 이용하여 다양한 결과를 표현한다.

<!-- 자바스크립트 표현식 예제 -->
...
<div id="app">
    <p>{{ message }}</p>
    <p>{{ message + "!!!" }}</p>
    <p>{{ message.split('').reverse().join('') }}</p>
</div>
...
<script>
    new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue.js!'
        }
    });
</script>

첫 번째 <p>태그는 message의 값 Hello Vue.js!를 그대로 출력한다. 두 번째 <p> 태그는 message 값에 문자열 !!!를 추가하여 출력하기 때문에 Hello Vue.js!!!!가 출력된다. 세 번째 <p> 태그는 문자열 Hello Vue.js!의 순서를 바꿔 !sj.euV olleH로 출력한다.


자바스크립트 표현식에서 주의할 점

자바스크립트 표현식을 사용할 때 주의할 점이 두 가지 있다. 첫째, 자바스크립트의 선언문과 분기 구문은 사용할 수 없다. 둘째, 복잡한 연산은 인스턴스 안에서 처리하고 화면에는 간단한 연산 결과만 표시해야 한다.

<!-- 자바스크립트 표현식에서 주의할 점 -->
...
<div id="app">
    <!-- {{ var a = 10; }} X, 선언문은 사용 불가능 -->
    <!-- {{ if(true) {return 100} }} X, 분기 구문은 사용 불가능 -->
    {{ true ? 100 : 0 }}<br/> <!-- O, 삼항 연산자로 표현 가능 -->

    {{ message.split('').reverse().join('') }}<br/> <!-- X, 복잡한 연산은 인스턴스 안에서 수행 -->
    {{ reversedMessage }} <!-- O, 스크립트에서 computed 속성으로 계산한 후 최종 값만 표현 -->
</div>
...
<script>
    new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue.js!'
        },
        computed: {
            reversedMessage: function() {
                return this.message.split('').reverse().join('');
            }
        }
    });
</script>

자바스크립트 선언문이나 분기 구문을 브라우저로 실행하면 오류가 발생한다. 분기 구문은 위 예제와 같이 삼항 연산자로 대체하여 사용할 수 있다.

그리고 message의 텍스트 값을 역순으로 변환하는 연산은 HTML 단에서 수행하지 않고, 자바스크립트 단에서 computed 속성을 이용하여 계산한 후 최종 결과 값만 표시한다. 이렇게 하면 화면단 코드의 가독성을 높일 수 있어 화면의 UI 구조를 쉽게 파악할 수 있다.

또 반복적인 연산에 대해 미리 계산하여 저장해 놓고, 필요할 때 바로 불러오는 캐싱(caching) 효과를 얻을 수 있다.


디렉티브

뷰 디렉티브(Directive)란 HTML 태그 안에 v- 접두사를 가지는 모든 속성들을 의미한다. 위에서 언급된 v-bind 속성도 디렉티브에 해당된다. 디렉티브의 형식은 다음과 같다.

<!-- 디렉티브 형식 -->
<a v-if="flag">두잇 Vue.js</a>

디렉티브는 화면의 요소를 더 쉽게 조작하기 위해 사용하는 기능이다. 뷰의 데이터 값이 변경되었을 때 화면의 요소들이 리액티브(Reactive)하게 반응하여 변경된 데이터 값에 따라 갱신된다. 이런 식으로 화면의 요소를 직접 제어할 필요 없이 뷰의 디렉티브를 활용하여 화면 요소들을 조작할 수 있다.

동적인 웹 앱을 구현할 때 자주 사용하는 주요 디렉티브는 다음과 같다.

디렉티브 이름역할
v-if지정한 부 데이터 값의 참, 거짓 여부에 따라 해당 HTML 태그를 화면에 표시하거나 표시하지 않는다.
v-for지정한 뷰 데이터의 개수만큼 해당 HTML 태그를 반복 출력한다.
v-showv-if와 유사하게 데이터의 진위 여부에 따라 해당 HTML 태그를 화면에 표시하거나 표시하지 않는다. 다만, v-if는 해당 태그를 완전히 삭제하지만 v-show는 css 효과만 display: none으로 주어 실제 태그는 남아 있고 화면상으로만 보이지 않는다.
v-bindHTML 태그의 기본 속성과 뷰 데이터 속성을 연결한다.
v-on화면 요소의 이벤트를 감지하여 처리할 때 사용한다. 예를 들어, v-on:click은 해당 태그의 클릭 이벤트를 감지하여 특정 메서드를 실행할 수 있다.
v-model폼(form)에서 주로 사용되는 속성이다. 폼에 입력한 값을 뷰 인스턴스의 데이터와 즉시 동기화한다. 화면에 입력된 값을 저장하여 서버에 보내거나 watch와 같은 고급 속성을 이용하여 추가 로직을 수행할 수 있다. <input>, <select>, <textarea> 태그에만 사용할 수 있다.

각 디렉티브의 동작을 확인하기 위해 다음 코드를 보자.

<html>
<head>
    <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>
        <button v-on:click="popupAlert">경고 창 버튼</button>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
    <!-- <script src="https://unpkg.com/vue-router@3.0.1/dist/vue-router.js"></script> -->
    <script>
        new Vue({
            el: '#app',
            data: {
                flag: true,
                systems: ['android', 'ios', 'window'],
                uid: 10
            },
            methods: {
                popupAlert: function() {
                    return alert('경고창 표시');
                }
            }
        });
    </script>
</body>
</html>

위 코드를 자세히 살펴보자.

  1. v-if : 분기 처리의 조건 값인 flag 값이 true 이므로 ‘두잇 Vue.js’ 텍스트를 화면에 표시한다.
  2. v-for : 뷰 데이터 systemsandroid, ios, window의 총 3개의 값을 가지는 배열이다. 이 배열의 요소 개수만큼 <li>태그가 반복되어 {{ system }}으로 각 요소의 값을 화면에 표시한다.
  3. v-show : v-if와 마찬가지로 flag 값이 true이므로 ‘두잇 Vue.js’를 화면에 표시한다.
  4. v-bind : HTML 태그의 id 속성을 뷰 데이터에 선언한 uid 값과 연결하여 화면에 표시한다.
  5. v-on : [경고 창 버튼]을 클릭했을 때 해당 이벤트를 감지하여 methods 속성에 선언한 popupAlert()메서드를 수행한다. 결과적으로 브라우저 기본 경고 창을 연다.


이벤트 처리

웹 앱에서 사용자의 클릭이나 키보드 입2력과 같은 이벤트를 처리하는 것은 당연하다. 뷰 역시 화면에서 발생한 이벤트를 처리하기 위해 v-on 디렉티브와 methods 속성을 활용한다. 제이쿼리 못지않게 뷰도 이벤트 처리가 매우 간단하다. 그럼 다음 코드로 간단한 버튼 클릭 이벤트를 처리해보자.

<div id="app">
    <button v-on:click="clickBtn">클릭</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        methods: {
            clickBtn: function() {
                alert('clicked');
            }
        }
    });
</script>

위 코드는 <button> 태그에 v-on:click 디렉티브를 추가하여 [클릭] 버튼을 클릭하면 clickBtn() 메서드가 실행되도록 지정했고 [클릭] 버튼을 클릭하면 methods 속성의 clickBtn() 메서드에 정의한 alert() 내장 API가 실행된다.

그리고 v-on 디렉티브로 메서드를 호출할 때 아래와 같이 인자 값을 넘기는 방법도 있다.

<div id="app">
    <button v-on:click="clickBtn(10)">클릭</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        methods: {
            clickBtn: function(num) {
                alert('clicked ' + num + ' times');
            }
        }
    });
</script>

마지막으로 event 인자를 이용해 화면 요소의 돔 이벤트에 접근해 보자.

<div id="app">
    <button v-on:click="clickBtn">클릭</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        methods: {
            clickBtn: function(event) {
                console.log(event);
            }
        }
    });
</script>

HTML 태그에서 v-on:click으로 호출하는 메서드에 인자를 전달하지 않아도 clickBtn: function(event) {}와 같이 event 인자를 정의하면 해당 돔 요소의 이벤트 객체에 접근할 수 있다. 브라우저 개발자도구의 콘솔 탭을 열고 코드를 실행한 후 [클릭] 버튼을 클릭하면 이벤트 객체가 콘솔에 출력되는 것을 확인할 수 있다.


고급 템플릿 기법

고급 템플릿 기법은 실제 애플리케이션을 개발할 때 유용한 속성으로, 위에서 살펴본 데이터 바인딩, 디렉티브와 같은 기본적인 문법과 함께 사용한다.


computed 속성

데이터를 가공하는 등의 복잡한 연산은 뷰 인스턴스 안에서 하고 최종적으로 HTML에는 데이터를 표현만 하는 것이 좋다. computed속성은 이러한 데이터 연산들을 정의하는 영역이다. 위에서 자바스크립트 표현식을 설명할 때 이미 아래의 예제를 살펴보았다.

<!-- computed 속성을 이용한 문자열 순서 변환 코드 -->
...
<div id="app">
    {{ reversedMessage }}
</div>
...
<script>
    new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue.js!'
        },
        computed: {
            reversedMessage: function() {
                return this.message.split('').reverse().join('');
            }
        }
    });
</script>

HTML에 바로 {{ message.split('').reverse().join('') }}를 정의할 수도 있지만 위 코드처럼 computed속성인 reversedMessage를 활용하면 HTML 표현단의 코드가 더 깔끔해진다.

computed속성의 첫 번째 장점은 data속성 값의 변화에 따라 자동으로 다시 연산한다는 점이다. 예를 들어, computed속성에서 data속성 값이 변경되면 전체 값을 다시 한 번 계산한다. 두 번째 장점은 캐싱이다.

여기서 캐싱의 특징을 정확히 이해하려면 methods속성을 언급하지 않을 수 없으므로 methods속성과 computed속성의 차이점을 알아보자.


`computed` 속성과 `methods` 속성의 차이점

일단 methods속성과 computed속성의 가장 큰 차이점은 methods속성은 호출할 때만 해당 로직이 수행되고, computed속성은 대상 데이터의 값이 변경되면 자동적으로 수행된다는 것이다. 다시 말해 수동적으로 데이터를 갱신하느냐, 능동적으로 데이터를 갱신하느냐의 차이점이 있다.

위 내용을 다음 예제 코드로 살펴보자.

<!-- computed 속성과 methods 속성의 차이점 -->
...
<div id="app">
    <p>{{ message }}</p>
    <button v-on:click="reverseMsg">문자열 역순</button>
</div>
...
<script>
    new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue.js!'
        },
        methods: {
            reverseMsg: function() {
                this.message = this.message.split('').reverse().join('');
                return this.message;
            }
        }
    });
</script>

위 코드는 앞에서 살펴본 computed속성으로 문자열 순서를 바꾼 코드와 동일한 결과를 낸다. 다만 차이점은 [문자열 역순] 버튼을 클릭했을 때만 문자열 순서를 역으로 변환한다는 것이다.

위의 차이점을 인지한 상태에서 다시 캐싱 면에서 두 속성을 보면 methods 속성은 수행할 때마다 연산을 하기 때문에 별도로 캐싱을 하지 않지만, computed속성은 데이터가 변경되지 않는 한 이전의 계산 값을 가지고 있다가(캐싱하고 있다가) 필요할 때 바로 반환해 준다. 따라서 복잡한 연산을 반복 수행해서 화면에 나타내야 한다면 computed속성을 이용하는 것이 methods속성을 이용하는 것보다 성능 면에서 효율적이다.


watch 속성

watch속성은 데이터 변화를 감지하여 자동으로 특정 로직을 수행한다. computed속성과 유사하지만 computed속성은 내장 API를 활용한 간단한 연산 정도로 적합한 반면에, watch속성은 데이터 호출과 같이 시간이 상대적으로 더 많이 소모되는 비동기 처리에 적합하다.

watch속성이 어떻게 동작하는지 확인하기 위해 다음 코드를 살펴보자.

<!-- watch 속성 예제 -->
...
<div id="app">
    <input v-model="message">
</div>
...
<script>
    new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue.js!'
        },
        watch: {
            message: function(data) {
                console.log("message의 값이 바뀝니다 : ", data);
            }
        }
    });
</script>

위 코드는 간단한 인풋 박스(input box)의 입력 값을 v-model 디렉티브로 연결하여 입력 값에 변화가 있을 때마다 watch속성에서 변화된 값을 로그로 출력한다.

'JavaScript > Vue.js' 카테고리의 다른 글

Vue.js 슬롯 (slot) 정리  (0) 2021.08.08
Vue Router :: Router 인스턴스와 Route 객체 비교  (0) 2021.08.08
VUE.JS의 EVENT 처리  (0) 2019.07.27
[Vue.js] 뷰 컴포넌트  (0) 2019.01.14
[Vue.js] 뷰 인스턴스  (0) 2019.01.14
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크