Study/Vue.js

[Vue3] Vue 템플릿 문법 (Mustache, Directive)

geehyun 2025. 3. 2. 01:08
반응형

[Vue3] Vue 템플릿 문법 (Mustache, Directive)


Vue 탬플릿 문법

탬플릿(Template)란 기본적으로 UI를 구성하는 틀로, 웹 개발에서는 HTML을 기반으로 화면을 구성하는 요소를 탬플릿이라 볼 수 있다.
Vue에서는 단순 정적 탬플릿이 아니라 데이터의 변화에 따라 동적으로 반응하여, 반응형 데이터를 바인딩할 수 있도록 설계되어 있다.

1. Mustache 문법

<p>{{ message }}</p>

 

{{}} 형식으로 작성하는 문법으로, 데이터를 바인딩할 때 쓰인다.
{{ 변수 }} 형식으로 작성하여 변수에 들어있는 데이터를 화면에 표시해주는 역할을 한다.

📌나 Mustache 라는걸 들어봤어요! 어디서 들었더라?
Mustache.js라는 탬플릿엔진에서 쓰이던 문법으로 원래는 HTML을 그리는 시점에 들어온 데이터를 바인딩하는 정적 데이터 바인딩 문법이었으나, Vue에서 이를 차용하여 반응형 데이터를 바인딩할 수 있도록 지원하는 Vue Mustache 문법을 제공한다.

특징

  • 단방향 데이터 바인딩
    • {{}} 안에 들어있는 변수의 데이터가 변경되면 자동으로 UI가 업데이트된다.
    • 다만, 사용자가 값을 변경할 수는 없는 단방향 데이터 바인딩 방식.
  • 자바스크립트 표현식 사용가능
    • 다만 if/else, for와 같은 문법은 구현 불가
<p>{{ text.toUpperCase() }}</p>
<p>{{ count * 2 }}</p>

사용법

작성 코드

<script setup lang="ts">
import {ref} from "vue";

const name = ref('지현');
</script>

<template>
  <h1>Vue 탬플릿 문법</h1>

  <h2>1. Mustache </h2>
  <div>안녕하세요? {{ name }} 님! Vue 세상에 오신걸 환영합니다.</div>
</template>

출력 화면

mustache 문법 사용예시

 

2. 디렉티브(Directive)

Vue에서 HTML 요소를 조작하거나 HTML 요소의 속성을 조작할 수 있다.
v- 접두어로 시작하면 HTML 태그의 속성처럼 작성하여 사용한다. (thymeleaf 에서 th- 문법과 유사)

1) v-bind

  • HTML 속성 값을 동적으로 바인딩할 수 있다.
  • v-bind:속성이름="값" 또는 :속성이름="값" 의 형식으로 작성한다.

작성 코드

<script setup lang="ts">
    import { ref } from 'vue'
    const geeDevBlog = ref('https://geehyun.tistory.com/');
</script>
<template>
    <strong>1. 기본형</strong>
    <a v-bind:href="geeDevBlog">GeeDev 블로그에 놀러오세요 1</a>

    <strong>2. 단축형</strong>
    <a :href="geeDevBlog">GeeDev 블로그에 놀러오세요 2</a>
</template>

출력 화면

v-bind 문법 사용예시

2) v-if

  • 입력된 조건이 true일 경우만 해당 태그를 렌더링 한다.
  • 즉, 조건이 false일 경우 렌더링 된 HTML 문서상 아예 존재하지 않는다. (DOM 에서 아예 존재 X)
  • v-if="조건" 의 형식으로 사용되며, 조건에서 간단한 연산자나 함수를 사용할 수 있다.

작성 코드

<script setup lang="ts">
    import { ref } from 'vue'
    const cost1 = ref(5000);
    const cost2 = ref(20000);
</script>
<template>
    <p>{{cost1}} <span v-if="cost1 > 10000">만원 초과!!!</span><span v-else>만원 미초과!!!</span></p>
    <p>{{cost2}} <span v-if="cost2 > 10000">만원 초과!!!</span><span v-else>만원 미초과!!!</span></p>
</template>

출력 화면

v-if 문법 사용예시

3) v-show

  • 입력된 조건이 true일 경우만 화면에 표시한다.
  • 조건이 truefalse이든 렌더링은 하며, 다만, 조건이 false일 경우 display:none; 처리된다. (조건이 false 이더라도 DOM 에는 존재함)
  • 그 외 사용법은 v-if와 동일하다.

작성코드

<script setup lang="ts">
    import { ref } from 'vue'
    const odd = ref(5);
</script>
<template>
    <p>{{odd}}는</p>
    <p v-show="odd % 2 != 0">홀수</p>
    <p v-show="odd % 2 == 0">짝수</p>
    <p>입니다.</p>
</template>

출력화면

v-show 문법 사용예시

4) v-for

  • 배열이나 객체를 반복하여 작성한 요소를 자동으로 생성한다.
  • v-for="변수 in 배열(또는 객체)" 로 사용하거나, v-for="(변수, 인덱스변수) in 배열(또는 객체)"로 인덱스(또는 키)를 사용할 수 있다.
  • :key 로 해당 배열(또는 객체)의 고유의 식별자를 지정해 줄 수 있다.
    • 식별자의 경우 객체의 key처럼 중복되지 않은 고유한 값을 사용해야 한다. (없으면 인덱스라도 사용 권장)
    • vue가 해당 배열(또는 객체)의 데이터를 구분하는 고유한 식별자로 성능 최적화, 올바른 업데이트 등을 위해 사용하는 것이 좋다.

작성코드

<script setup lang="ts">
    import { ref } from 'vue'
    const nameArray = ref(['지현', '김아무개', '홍길동', '김철수', '김영희']);
    const nameObj = ref<Record<string, any>>({"name": "geehyun", "age": "5살", "gender" : "female"});
</script>
<template>
    <strong>1. for of 사용</strong>
    <p v-for="name of nameArray">저는 {{name}} 입니다.</p>

    <strong>2. for index 사용</strong>
    <p v-for="(item, index) of nameArray" :key="index">저는 {{index + 1}} 번째 이름 {{item}} 입니다.</p>
    <hr>
    <p v-for="(item, id) of nameObj" :key="id">저의 {{id}} 는 {{item}} 입니다.</p>
</template>

출력화면

v-for 문법 사용예시

5) v-model

  • 양방향 데이터 바인딩을 제공한다.
  • input, textarea, select 등의 form 요소와 연결하여 사용자가 값을 입력(또는 선택) 할 시 자동으로 Vue 데이터도 변경되고, Vue 데이터가 변경되면 입력 필드의 값이 변경되는 양방향 데이터 바인딩 기능이다.

작성코드

<script setup lang="ts">
    const input = ref('입력 전');
</script>
<template>
    <input v-model="input" placeholder="이름을 입력하세요">
    <br>
    <p>저는 {{input}} 입니다.</p>
</template>

출력화면

v-model 문법 사용예시 (사용자 입력 전)
v-model 문법 사용예시 (사용자 입력 후)

6) v-on

  • 각 이벤트 별 이벤트 핸들러를 등록할 수 있다.
  • v-on:이벤트명="값" 또는 @이벤트명="값"의 형태로 사용할 수 있다.

작성코드

<script setup lang="ts">
    const count1 = ref(0);
    const count2 = ref(0);
    const count3 = ref(0);
    const count4 = ref(0 as number);
    const inputNum = ref(0);
    const add1 = ()=>{count3.value++;};
    const addNum = (num:number)=>{count4.value+=num;};
</script>
<template>
    <strong>1. 기본형</strong>
    <button v-on:click="count1++">+1</button>
    <p>count1 : {{count1}}</p>

    <strong>2. 단축형</strong>
    <button @click="count2++">+1</button>
    <p>count2 : {{count2}}</p>

    <strong>3. 함수사용 : 인자없음</strong>
    <button @click="add1">add1</button>
    <p>count3 : {{count3}}</p>

    <strong>4. 함수사용 : 인자있음</strong>
    <input v-model="inputNum" type="number"></input>
    <button @click="addNum(inputNum)">+</button>
    <p>count4 : {{count4}}</p>
</template>

출력화면

v-on 문법 사용예시 (이벤트 발생 전)
v-on 문법 사용예시 (이벤트 발생 후)

7) v-html

  • HTML 태그가 포함된 문자열을 실제 HTML로 렌더링 할 수 있다. (JavaScript에서 innerHTML과 유사)
  • 단, 사용 시 사용자 입력 값을 v-html로 바로 출력하는 것은 보완적으로 위험할 수 있으며, XSS 공격에 유의해야 한다.

작성코드

<script setup lang="ts">
    const htmlContents = ref(`<table style="border: 1px solid black"><tr><th>항목 1</th><td>항목2</td></tr><tr><td>내용 1</td><td>내용 2</td></tr></table>`);
</script>

<template>
    <strong> 1. v-html 로 넣었을 때</strong>
    <div v-html="htmlContents"></div>
    <strong v-pre> 2. {{}} 로 넣었을 때</strong>
    <div>{{htmlContents}}</div>
</template>

출력화면

v-html 문법 사용예시

8) v-text

  • 내용을 텍스트로 삽입할 때 사용된다. (JavaScript에서 textContent와 유사)
  • HTML 또는 JavsScript 등 코드가 들어와도 텍스트 그대로 화면에 출력한다.

작성코드

<template>
    <strong> 1. v-text 로 넣었을 때</strong>
    <div v-text="htmlContents"></div>
    <strong v-pre> 2. {{}} 로 넣었을 때</strong>
    <div>{{htmlContents}}</div>
</template>

<script setup lang="ts">
    const htmlContents = ref(`<table style="border: 1px solid black"><tr><th>항목 1</th><td>항목2</td></tr><tr><td>내용 1</td><td>내용 2</td></tr></table>`);
</script>

출력화면

v-text 문법 사용예시

9) v-slot

  • slot이란 vue에서 부모 컴포넌트가 자식 컴포넌트의 특정 영역을 직접 정의하는 기능으로, v-slot으로 이러한 slot을 제어할 수 있다.
  • 부모 컴포넌트에서 slot <template v-slot:슬릇명>으로 슬롯을 지정하고, 자식 컴포넌트에서 <slot name="슬릇이름"> 으로 사용할 수 있다.
  • <template v-slot:슬릇명> 또는 <template #슬릇명> 으로 사용할 수 있다. 또한, <template v-slot:default> 로 default로 설정한 slot에 대해서는 자식 컴포넌트에서 <slot>의 형식만으로도 사용할 수 있다.
  • 또한, slot을 사용할 때 부모 컴포넌트는 자식 컴포넌트의 데이터를 받아 해당 데이터를 활용하여 해당 slot 내에서 사용할 수 있다. 이를 Scoped Slot 이라 한다.

작성코드

<!-- 부모 영역 : Parent.vue -->
<template>
    <ChildComponent>
        <template v-slot:default>
            <p>안녕 난 부모 영역이야! 이름 없는 slot 이지!</p>
        </template>
        <template v-slot:test1>
            <p>난 test1 라는 이름의 slot 이야. 기본형으로 사용했지 </p>
        </template>
        <template #test2>
            <p>난 test2 라는 이름의 slot 이야. 단축형으로 사용했어 </p>
        </template>
        <template #test3="{data}">
            <p>난 test3 라는 이름의 slot 이야. 아래는 자식 컴포넌트에서 받은 데이터로 출력한거야</p>
            <p v-for="(item, key) in data" :key="key">key : {{ key }} / item : {{ item }}</p>
        </template>
    </ChildComponent>
</template>

<!-- 자식 영역 : ChildComponent.vue -->
<template>
    <strong> 1. default slot 사용</strong>
    <slot></slot>
    <strong> 2. named slot 사용 : 기본형</strong>
    <slot name="test1"></slot>
    <strong> 3. named slot 사용 : 단축형</strong>
    <slot name="test2"></slot>
    <strong> 4. scoped slot 활용</strong>
    <slot name="test3" :data="childData"></slot>
</template>

출력화면

v-slot 문법 사용예시 (작성코드)
v-slot 문법 사용예시 (출력 내용)

10) v-cloak

  • Vue가 화면을 완전히 로드할 때까지 해당 태그를 아예 화면에서 보이지 않게 처리할 수 있게 할 수 있다.
  • 네트워크 환경이 느리거나, 불러올 요소가 많은 경우 Vue가 화면을 완전히 렌더링 하기 전 {{변수}}와 같은 vue 문법들이 텍스트 그대로 화면에 표시되는 경우가 있다. 이를 방지하기 위해 v-cloak을 사용할 수 있다.
  • Vue가 화면을 완전히 렌더링 하기 전 v-cloak을 넣은 요소에 v-cloak HTML 속성에 추가하여 CSS Style 로 display:none 처리 또는 커스텀 로딩중 처리 등으로 사용할 수 있다. (v-cloak 속성 자체가 처리해 주는 게 아니기 때문에 별도 CSS 처리 필요)
  • v-cloak 사용 시 렌더링 완료 전 v-cloak HTML 속성이 추가되며, 렌더링 완료 후 v-cloak HTML 속성이 제거된다.

작성코드

<script setup lang="ts">
    const message = ref('로딩 완료~');
</script>

<template>
    <div v-cloak>{{message}}</div>
</template>

<style>
    [v-cloak] {
        display: none;
    }
</style>

출력화면

v-cloak 문법 사용예시
v-slot 문법 사용예시 (로딩 완료 후 html 요소에 v-cloak 속성 없는 부분 확인)

 

해당 문법의 경우! 보이지 않는 걸 캡처하기 어려워 랜더링 된 상태만 확인

11) v-pre

  • 해당 디렉티브 문법을 사용 시 해당 HTML 요소 하위에 있는 요소에서 Vue 탬플릿 문법을 해석하지 않도록 처리한다.
  • HTML 기본 태그 중 pre코드가 해당 태그 내 HTML 문법으로 작성된 내용도 HTML 문법으로 읽지 않고 텍스트 그대로 표시하는 것처럼, v-pre{{}} 등의 Vue 문법을 해석하지 않고 텍스트 그대로 표시하게 한다.

작성코드

<script setup lang="ts">
    const mustache = ref('전 mustache 에요! 콧수염같이 생겨서 이름이 이렇답니다.');
</script>

<template>
    <strong> 1. v-pre 사용</strong>
    <div v-pre>{{mustache}}</div>
    <strong> 2. v-pre 미사용</strong>
    <div>{{mustache}}</div>
</template>

출력화면

v-pre 문법 사용예시

12) v-memo

  • Vue3에서 새로 추가된 기능이며, 캐싱을 이용해 성능을 최적화할 수 있는 기능이다.
  • v-memo 에 입력된 값 기준으로 데이터의 변경 여부를 판단하여, 해당 값이 변경되지 않으면 다시 렌더링 하지 않도록 한다.
  • 배열, 객체 데이터에서 특정 항목 기준으로 변경 여부를 판단하고, 그 외 다른 값이 변경되는 것은 변경으로 보지 않도록 하여 불필요한 렌더링을 줄이고, 성능을 최적화할 수 있다.

작성코드

<script setup lang="ts">
    const count = ref(0);
    const memo = ref('초기 값');
</script>

<template>
    <strong> 1. v-memo 사용</strong>
    <p v-memo="[count]"> count : {{count}} / memo : {{memo}}</p>
    <!-- count 값이 변경될 때만 렌더링 되며, memo의 값만이 변경될 때는 렌더링 되지 않는다. -->

    <strong> 2. v-memo 미사용</strong>
    <p> count : {{count}} / memo : {{memo}}</p>
    <!-- count, memo 값 각각 변경될 때마다 렌더링 된다. -->

    <button @click="count++">1 증가</button>
    <button @click="memo+= '+' + count">메모 더하기</button>
</template>

출력화면

v-memo 문법 사용예시 (값 변경 전)
v-memo 문법 사용예시 (count 값 변경 => v-memo 사용/미사용 모두 같이 변경된 값으로 렌더링 됨.)
v-memo 문법 사용예시 (memo 값 변경 => v-memo 사용한경우 변경되지 않고, 미사용한 경우에만 변경 됨.)

 

마치며

vue 탬플릿 문법에 대해 공부해 봤는데, thymeleaf를 먼저 사용해 왔던 사람으로서 꽤나 thymeleaf 문법과 유사하다고 느껴졌다.

기존 HTML/CSS/JavaScript 로도 구현이 가능하지만, Vue를 이용한다면 더욱 편하게 사용할 수 있을 것 같다.

특히 v-memo와 v-slot 은 공부하면서 많이 신기했고 앞으로 공부할 Vue 컴포넌트와 함께 Vue 만의 특화된 기능으로 여러 가지 상황에서 활용할 수 있을 것 같다.

 

꽤나 흥미롭게 Vue 공부를 하고 있다.

728x90