[JavaScript][Vue.js] Vue Directive 문법 정리 - v-bind부터 v-if, v-for까지

2026. 8. 24. 22:16·개발/JavaScript
반응형

Vue에서 <template>을 작성하다 보면 일반 HTML에서는 볼 수 없었던 속성들이 등장한다.

v-html
v-bind
v-if
v-show
v-for

이처럼 v-로 시작하는 Vue 전용 특수 속성을 Directive(디렉티브)라고 한다.

Directive를 사용하면 HTML 태그와 JavaScript 데이터를 연결하여 화면의 내용, 속성, 스타일, 조건, 반복 등을 동적으로 제어할 수 있다.

 

Vue의 Directive에서 특히 중요한 점은 다음과 같은 코드에서

<img :src="imageUrl">

"imageUrl"이 단순한 문자열이 아니라 JavaScript 표현식이 실행되는 영역이라는 것이다.

즉 Vue의 Template은 단순한 HTML이 아니라 JavaScript 데이터와 연결되어 동적으로 변경되는 화면이라고 볼 수 있다.


데이터를 화면에 출력하는 방법

Vue에서 데이터를 화면에 출력하는 가장 기본적인 방법은 {{ }}를 사용하는 것이다.

<script setup>
const message = 'Hello Vue'
</script>

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

화면에는 다음과 같이 출력된다.

Hello Vue

이를 Text Interpolation(텍스트 보간법)이라고 한다.

하지만 문자열 안에 HTML 코드가 들어 있다면 상황이 조금 달라진다.

const message = '<strong>Hello Vue</strong>'

일반 보간법으로 출력하면

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

화면에는 HTML이 적용되는 것이 아니라 문자열 그대로 출력된다.

<strong>Hello Vue</strong>

v-html

문자열을 실제 HTML Element로 해석해서 출력하고 싶다면 v-html을 사용할 수 있다.

<script setup>
const rawHtmlData =
  '이 글자는 <span style="color:red; font-weight:bold;">빨간색 굵은 글자</span>이다.'
</script>

<template>
  <p v-html="rawHtmlData"></p>
</template>

v-html은 JavaScript의 innerHTML과 유사하게 동작한다.

개념적으로 보면 다음과 같다.

{{ data }}
    ↓
문자열 그대로 출력

v-html="data"
    ↓
HTML로 해석하여 출력

다만 v-html을 사용할 때는 XSS(Cross-Site Scripting)에 주의해야 한다.

사용자가 입력한 값을 그대로 v-html에 넣으면 해당 문자열이 HTML로 해석되기 때문에 악의적인 코드가 브라우저에서 실행될 위험이 있다.

게시판이나 입력창에 악성 코드가 삽입되고, 다른 사용자가 이를 조회할 때 실행되는 상황을 XSS의 대표적인 위험이다.

 

따라서 일반적으로는

{{ data }}

를 사용하고, 신뢰할 수 있는 HTML을 반드시 렌더링해야 할 때만 v-html을 사용하는 것이 좋다.


v-text

v-text도 데이터를 텍스트로 출력하는 Directive다.

<script setup>
const content = '안녕하세요! Vue 강의입니다.'
</script>

<template>
  <p v-text="content"></p>
</template>

이는 일반 보간법과 거의 같은 역할을 한다.

<p>{{ content }}</p>

자료에서도 v-text는 텍스트 내용을 채워 넣으며, 일반적인 경우에는 v-text보다 {{ }}를 주로 사용하는 방식으로 설명하고 있다.

따라서 세 가지를 비교하면 다음과 같다.

문법 역할
{{ data }} 데이터를 텍스트로 출력
v-text="data" 데이터를 텍스트로 출력
v-html="data" 데이터를 HTML로 해석하여 출력

HTML 속성과 Vue 데이터를 연결하는 v-bind

Vue에서 가장 많이 사용하는 Directive 중 하나가 v-bind다.

v-bind는 HTML의 Attribute와 JavaScript 데이터를 동적으로 연결하는 기능이다.

예를 들어 일반 HTML에서는 이미지 주소를 다음과 같이 고정한다.

<img src="/images/logo.png">

Vue에서는 이미지 주소를 변수로 관리할 수 있다.


const logoImgSrc = '<a href=https://vuejs.org/images/logo.png'>https://vuejs.org/images/logo.png'</a>

Vue에서 v-bind는 매우 자주 사용되기 때문에 일반적으로 다음과 같이 :로 축약한다.

<img :src="logoImgSrc">

즉

v-bind:src="logoImgSrc"

와

:src="logoImgSrc"

는 같은 의미다.

href, src, disabled 등 다양한 HTML 속성과 연결할 수 있다.

<a :href="dynamicUrl">사이트 이동</a>

<img :src="logoImgSrc">

<button :disabled="isButtonDisabled">
  버튼
</button>

전체적인 구조는 다음과 같이 이해하면 된다.

JavaScript 데이터
        ↓
      v-bind
        ↓
HTML Attribute

class도 동적으로 변경할 수 있다

v-bind는 단순히 src, href와 같은 속성만 연결하는 것이 아니다.

CSS 클래스도 데이터 상태에 따라 동적으로 추가하거나 제거할 수 있다.

 

가장 대표적인 방법은 객체 형태다.

<p :class="{ 'text-danger': isWarning }">
  경고 메시지
</p>

isWarning이

true

이면 text-danger 클래스가 적용되고,

false

이면 클래스가 제거된다.

즉 다음과 같다.

isWarning = true
        ↓
class="text-danger"

isWarning = false
        ↓
클래스 제거

Vue에서는 여러 개의 클래스를 배열 형태로 조합하는 것도 가능하다.

<div
  :class="[
    themeClass,
    isWarning ? 'border-red' : 'border-gray'
  ]"
>
  내용
</div>

:class가 객체와 배열 형식을 지원하며, 객체에서는 Boolean 조건으로 클래스 포함 여부를 정하고 배열에서는 여러 클래스를 조합할 수 있다.


style도 동적으로 변경할 수 있다

인라인 스타일 역시 v-bind로 연결할 수 있다.

<script setup>
const textColor = 'purple'
const fontSize = 20
</script>

<template>
  <p :style="{
    color: textColor,
    fontSize: fontSize + 'px'
  }">
    Hello Vue
  </p>
</template>

Vue에서는 style 객체의 CSS 속성명을 일반적으로 camelCase로 작성한다.

backgroundColor
fontSize
fontWeight

여러 스타일 객체를 합칠 수도 있다.

<div :style="[baseStyle, borderStyle]">
  Box
</div>

:style은 객체와 배열을 지원하며, 실시간으로 색상이나 크기 같은 CSS 값을 변경할 때 사용할 수 있다.

다만 대부분의 일반적인 디자인 변경은 :style보다 :class를 사용하는 것이 관리하기 편하다.

:class
→ 미리 만들어놓은 CSS 디자인을 조건에 따라 적용

:style
→ 색상, 크기 등의 값을 직접 동적으로 변경

예를 들어 다크모드나 경고 상태처럼 이미 정의한 디자인을 전환할 때는 :class가 적합하고, 프로그레스바 너비처럼 숫자가 계속 변하는 경우에는 :style이 적합하다.


Vue 3.4의 v-bind 축약 문법

Vue 3.4부터는 HTML 속성명과 JavaScript 변수명이 같다면 더 짧게 작성할 수도 있다.

기존에는

<img :src="src">

라고 작성했다면,

<img :src>

처럼 사용할 수 있다.

예를 들어


const id = 'user-profile-card'
const src = '<a href=https://vuejs.org/images/logo.png'>https://vuejs.org/images/logo.png'</a>

과 같이 작성한다.

즉

:src="src"

에서 이름이 동일하기 때문에

:src

만 남긴 것이다.


조건에 따라 화면을 바꾸는 v-if와 v-show

웹 화면에서는 로그인 여부나 데이터 상태에 따라 특정 요소를 보여주거나 숨겨야 하는 경우가 많다.

Vue에서는 이를 위해 v-if를 사용한다.

<script setup>
import { ref } from 'vue'

const isLogged = ref(false)
</script>

<template>
  <p v-if="isLogged">
    환영합니다.
  </p>

  <p v-else>
    로그인이 필요합니다.
  </p>
</template>

isLogged 값에 따라서 두 요소 중 하나가 렌더링된다.

isLogged = true

→ 환영합니다.


isLogged = false

→ 로그인이 필요합니다.

JavaScript의 if / else if / else처럼 여러 조건도 사용할 수 있다.

<div v-if="score >= 90">
  A 학점
</div>

<div v-else-if="score >= 80">
  B 학점
</div>

<div v-else-if="score >= 70">
  C 학점
</div>

<div v-else>
  F 학점
</div>

v-if, v-else-if, v-else는 조건에 따라 실제 DOM 요소를 생성하거나 제거하는 방식으로 동작한다.


v-show는 무엇이 다를까

v-show도 조건에 따라 화면을 보여주거나 숨긴다.

<div v-show="isVisible">
  화면에 표시할 영역
</div>

그러나 v-if와 동작 방식이 다르다.

v-if는 조건이 false이면 실제 DOM에서 요소를 제거한다.

v-if = false

DOM에서 제거

반면 v-show는 DOM 요소를 그대로 유지한 상태에서 CSS를 사용한다.

display: none;

즉

v-show = false

DOM에는 존재
↓
display: none
↓
화면에서만 숨김

이다.

 

두 방식을 비교하면 다음과 같다.

구분 v-if v-show
false일 때 DOM에서 제거 DOM 유지
동작 방식 DOM 생성/삭제 display 변경
초기 렌더링 비용 낮음 상대적으로 높음
반복적인 화면 전환 상대적으로 부담 유리
v-else 사용 가능 불가능

따라서 화면이 거의 변경되지 않는 경우라면 v-if를,

로그인 권한
관리자 메뉴
특정 데이터 존재 여부

처럼 사용할 수 있다.

반대로 자주 열고 닫는 UI라면 v-show가 적합하다.

Modal
Tab
Accordion
Dropdown

이와 같은 기준으로 v-if와 v-show를 구분하고 있다.


반복되는 화면을 만드는 v-for

웹에서는 같은 형태의 데이터를 반복해서 출력하는 경우가 매우 많다.

예를 들어 과일 목록이 있다고 해보자.

const fruits = ['사과', '바나나', '딸기']

HTML을 직접 작성한다면

<li>사과</li>
<li>바나나</li>
<li>딸기</li>

처럼 각각 만들어야 한다.

Vue에서는 v-for를 사용할 수 있다.

<li
  v-for="fruit in fruits"
  :key="fruit"
>
  {{ fruit }}
</li>

배열의 index도 함께 받을 수 있다.

<li
  v-for="(fruit, index) in fruits"
  :key="index"
>
  {{ index + 1 }}번 과일: {{ fruit }}
</li>

구조를 보면

fruits

['사과', '바나나', '딸기']

          ↓

        v-for

          ↓

<li>사과</li>
<li>바나나</li>
<li>딸기</li>

가 된다.

객체 역시 반복할 수 있다.

const user = {
  name: '홍길동',
  age: 25,
  role: '개발자'
}
<li
  v-for="(value, key) in user"
  :key="key"
>
  {{ key }} : {{ value }}
</li>

그리고 실제 개발에서 가장 자주 만나는 형태는 객체를 가진 배열이다.

const items = [
  { id: 'prod_101', name: '아이폰' },
  { id: 'prod_102', name: '갤럭시' }
]
<li
  v-for="item in items"
  :key="item.id"
>
  {{ item.name }}
</li>

v-for를 사용할 때 Vue가 각각의 요소를 고유하게 구분할 수 있도록 :key를 함께 지정하는 것을 중요한 규칙으로 설명한다.

따라서 일반적으로

v-for="item in items"
:key="item.id"

를 하나의 세트처럼 기억하는 것이 좋다.

특히 고유한 id가 있다면 index보다 해당 id를 key로 사용하는 방식이 적절하다.


알아두면 좋은 기타 Directive

앞에서 본 Directive들은 Vue 개발에서 매우 자주 사용한다.

반면 다음 Directive들은 사용 빈도는 상대적으로 낮지만 Vue의 렌더링 원리를 이해하는 데 도움이 된다.

v-pre

v-pre는 Vue에게

이 영역은 Vue 문법으로 해석하지 말고 그대로 보여줘.

라고 알려주는 Directive다.

<script setup>
const message = '안녕하세요!'
</script>

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

  <p v-pre>
    {{ message }}
  </p>
</template>

첫 번째는

안녕하세요!

가 출력되지만,

v-pre가 적용된 두 번째는

{{ message }}

가 그대로 표시된다.

Vue의 Template Compiler가 해당 영역을 해석하지 않는 것이다.


v-cloak

Vue가 완전히 로딩되기 전에 화면이 먼저 나타나면 아주 잠깐

{{ message }}

같은 미완성 템플릿 문법이 사용자에게 보일 수 있다.

이를 방지하기 위한 Directive가 v-cloak이다.

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

그리고 CSS와 함께 사용한다.

[v-cloak] {
  display: none !important;
}

Vue의 렌더링이 끝날 때까지 화면을 숨겼다가, 준비가 완료되면 표시하는 방식이다.


v-once

Vue의 반응형 데이터는 값이 변경되면 화면도 다시 갱신된다.

하지만 한 번 출력된 후 절대 변경할 필요가 없는 데이터도 있을 수 있다.

 

이럴 때 v-once를 사용할 수 있다.

<p v-once>
  {{ count }}
</p>

count가 처음에 1이었다면 이 영역은 최초 렌더링 이후 count가 변경돼도 계속 1을 유지한다.

최초 count = 1
       ↓
v-once 렌더링
       ↓
화면 : 1
       ↓
count = 2
       ↓
화면 : 여전히 1

즉 최초 한 번만 렌더링하고 이후의 반응형 업데이트를 받지 않는다.


v-memo

v-memo는 조금 더 선택적인 렌더링 최적화 기능이다.

<div v-memo="[name]">
  <p>이름: {{ name }}</p>
  <p>나이: {{ age }}</p>
</div>

여기서는 name을 감시 대상으로 지정했다.

name 변경
   ↓
해당 영역 다시 렌더링

age만 변경
   ↓
기존 렌더링 결과 재사용

즉 지정된 값이 변경됐을 때만 해당 영역을 업데이트하고, 그렇지 않으면 이전에 렌더링한 결과를 재사용한다.

일반적인 작은 화면에서는 자주 사용할 필요가 없지만, 렌더링 비용이 큰 UI를 최적화해야 할 때 사용할 수 있는 Directive다.


Vue Directive 전체 흐름 정리

이번에 살펴본 Directive를 역할별로 묶으면 생각보다 간단하다.

Vue Directive
│
├─ 콘텐츠 출력
│   ├─ v-html
│   └─ v-text
│
├─ 데이터 연결
│   └─ v-bind (:)
│       ├─ Attribute
│       ├─ Class
│       └─ Style
│
├─ 조건
│   ├─ v-if
│   └─ v-show
│
├─ 반복
│   └─ v-for
│
└─ 렌더링 제어
    ├─ v-pre
    ├─ v-cloak
    ├─ v-once
    └─ v-memo

이 중 처음 Vue를 공부할 때 가장 중요하게 볼 것은 다음 정도다.

{{ }}
→ 화면에 데이터 출력

:
→ v-bind
→ HTML 속성에 데이터 연결

v-if
→ 조건에 따라 DOM 생성/삭제

v-show
→ 조건에 따라 표시/숨김

v-for
→ 배열이나 객체 반복 출력

그리고 다음 단계에서 여기에

@click
v-model

이 추가된다.

그러면 Vue Template의 기본적인 화면 제어 문법은 거의 완성된다.

실제로 Vue 코드를 보면 다음과 같은 형태가 매우 자주 등장한다.

<script setup>
import { ref } from 'vue'

const isLoggedIn = ref(true)

const users = ref([
  { id: 1, name: 'Kim' },
  { id: 2, name: 'Lee' },
  { id: 3, name: 'Park' }
])
</script>

<template>
  <div v-if="isLoggedIn">

    <h2>사용자 목록</h2>

    <ul>
      <li
        v-for="user in users"
        :key="user.id"
      >
        {{ user.name }}
      </li>
    </ul>

  </div>

  <p v-else>
    로그인이 필요합니다.
  </p>
</template>

처음에는 여러 문법이 섞여 있어 복잡해 보이지만 하나씩 해석하면 단순하다.

v-if
→ 로그인 상태 확인

v-for
→ users 반복

:key
→ 각각의 사용자 식별

{{ user.name }}
→ 사용자 이름 출력

결국 Vue의 Template 문법은 JavaScript 데이터와 HTML 화면을 연결하기 위한 문법이라고 볼 수 있다.

Vue에서는 개발자가 Real DOM을 직접 찾아서 수정하기보다,

데이터를 선언하고
      ↓
Directive로 HTML과 연결하고
      ↓
데이터를 변경하면
      ↓
Vue가 화면을 갱신한다

라는 흐름으로 개발하게 된다.

반응형

'개발 > JavaScript' 카테고리의 다른 글

[JavaScript][Vue.js] Props와 Emits 정리 - 부모·자식 컴포넌트 통신  (0) 2026.08.26
[JavaScript][Vue.js] Component Lifecycle과 Lifecycle Hook 정리  (0) 2026.08.26
[JavaScript][Vue.js] Composition API란? - Options API와의 차이부터 ref, computed, watch까지  (0) 2026.08.26
[JavaScript][Vue.js] Vue 기본 개념 이해하기  (0) 2026.08.24
[JavaScript] 비동기 처리 이해하기 - Callback부터 Promise, async/await까지  (0) 2026.08.24
'개발/JavaScript' 카테고리의 다른 글
  • [JavaScript][Vue.js] Component Lifecycle과 Lifecycle Hook 정리
  • [JavaScript][Vue.js] Composition API란? - Options API와의 차이부터 ref, computed, watch까지
  • [JavaScript][Vue.js] Vue 기본 개념 이해하기
  • [JavaScript] 비동기 처리 이해하기 - Callback부터 Promise, async/await까지
danieLee
danieLee
개발일지
  • danieLee
    Code log
    danieLee
  • 전체
    오늘
    어제
    • 분류 전체보기 (77)
      • 개발 (76)
        • C++ (3)
        • java (6)
        • JavaScript (9)
        • python (0)
        • AWS (2)
        • Docker (6)
        • git (0)
        • 백엔드 (4)
        • Spring (7)
        • Django (2)
        • AI (3)
        • 코테 준비 (13)
        • 알고리즘 (6)
        • SKALA 4기 (13)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    JavaScript
    프론트
    Ai
    코테
    vue.js
    개념
    알고리즘
    개발
    API
    js
    백엔드
    java
    대학생
    개발자
    프로그래머스
    4기
    파이썬
    서버
    skala
    spring
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.1
danieLee
[JavaScript][Vue.js] Vue Directive 문법 정리 - v-bind부터 v-if, v-for까지
상단으로

티스토리툴바