Vue Directives
Vue.js 컴포넌트 내에서 템플릿 문법을 확장하여 DOM을 조작하고 데이터를 바인딩하는 핵심 방법이 지시어(directive)다. Vue Template Syntax의 하위 개념이며 v-bind, v-model, v-if, v-show, v-for, v-on 같은 개별 지시어를 포함한다. 이 페이지가 답하는 질문은 "Vue에서 데이터를 DOM 엘리먼트에 어떻게 바인딩하고, 이벤트를 어떻게 처리하는가"다.
핵심 모델
- 지시어(Directives)의 정의:
v-접두사가 있는 특수한 HTML 속성(Attribute)이다. - 표현식의 제약: 지시어의 속성값은 원칙적으로 단일 JavaScript 표현식만 허용된다.
- 핵심 역할: 반응형(Reactive) 데이터가 변경될 때마다 이를 감지하여, DOM에 선언된 반응형 효과(상태 업데이트, 렌더링 변경 등)를 자동으로 적용한다.
- directive source는 template interpolation,
v-bind, class/style binding,v-model, conditional rendering, list rendering을 코드 예시로 설명한다.[1] 같은 source에서v-if는 조건이 false일 때 block을 만들지 않고,v-show는 element를 만든 뒤 CSS display를 전환한다고 구분한다.[1:1] - instance source는
v-on/@event binding과.stop,.prevent,.self,.once같은 event modifier를 설명한다.[2]
뷰(View)와 모델(Model)의 분리
Vue 지시어는 뷰와 모델 사이의 선언적 연결 고리를 제공하여, 개발자가 DOM을 직접 조작(Imperative)하는 대신 데이터 상태(State) 관리에만 집중하도록 돕는다고 볼 수 있다. 특히 v-model은 양방향 바인딩을 기본 제공하여, 복잡한 폼(Form) 처리 코드를 획기적으로 줄여준다는 점에서 폼 처리의 보일러플레이트를 없애는 역할이 크다.
이 지시어들은 반응성 시스템이 상태 변화를 감지해야 동작하며, Vue의 선언적 렌더링 방식을 설명한다. document.getElementById 같은 Vanilla JS DOM API나 JavaScript 내부에서 UI를 반환하는 React JSX 방식과 대비되고, Vue component 템플릿 내부에서 쓰인다.
경계
- vs 템플릿 보간법(
{{ }}): 보간법이 텍스트 노드의 값을 치환한다면, 지시어는 속성 값 자체를 바꾸거나 엘리먼트 렌더링 여부를 직접 제어한다. 보간법{{ }}내부에는 선언문(var a = 1)이나 제어문(if)을 사용할 수 없으므로, 대신 삼항 연산자를 활용하거나 메서드를 호출해야 한다. - XSS 취약점 주의:
v-html은 값을 HTML로 해석하므로 신뢰할 수 있는 content에만 사용한다.v-text는 text content를 설정하므로 같은 의미의 raw HTML injection API가 아니다.
메커니즘
주요 템플릿 구문 및 지시어 요약
지시어는 각각 DOM 엘리먼트에 특정 반응형 동작을 부여하는 고유한 메커니즘을 가진다.
v-bind(:): 속성 및 스타일 바인딩- 엘리먼트의 속성(attribute)이나 클래스/스타일 객체를 동적으로 바인딩한다.
:[key]="value"형태의 동적 인자 바인딩도 지원한다.
v-on(@): 이벤트 처리- 엘리먼트에 네이티브 DOM 이벤트 리스너를 연결한다.
v-if/v-else-if/v-else: 진짜 조건부 렌더링- 조건이
true일 때만 블록을 렌더링한다. false일 경우 DOM 트리에 엘리먼트를 아예 그리지 않거나 파괴한다.
- 조건이
v-show: 가시성 토글- 조건과 관계없이 DOM을 항상 렌더링(생성)한다.
- CSS의
display속성만을none으로 토글하여 가시성을 제어한다.
v-for: 리스트 렌더링- 배열이나 객체를 순회하여 요소를 반복 렌더링한다.
- 성능 최적화를 위해 반드시 각 항목을 식별할 수 있는 고유한
key를 바인딩해야 한다.
v-model: 양방향 바인딩- 폼 입력과 컴포넌트 상태 간 양방향 바인딩을 생성한다.
- 내부적으로
v-bind:value와v-on:input을 합친 신택스 슈가(Syntactic Sugar)로 동작한다. - 동작을 세밀하게 제어하기 위한 수식어(Modifiers)를 제공한다:
.lazy:input이벤트 대신change이벤트(포커스 이동 등) 발생 시 동기화..number: 사용자 입력을 자동으로 숫자 타입으로 형변환..trim: 입력값의 앞뒤 공백 자동 제거.
v-cloak: 렌더링 지연 시점 제어- Vue app이 mount를 완료하기 전까지
{{ }}보간법 text가 화면에 노출되는 현상을 숨긴다. [v-cloak] { display: none }CSS와 함께 사용하며, mount가 끝나면 Vue가 속성을 제거한다.
- Vue app이 mount를 완료하기 전까지
절충점
v-if vs v-show
두 지시어는 렌더링 비용과 토글 비용 사이에서 트레이드오프(Trade-off)를 가진다.
| 지시어 | 렌더링 방식 | 초기 렌더링 비용 | 조건 전환(토글) 비용 | 권장 사용처 |
|---|---|---|---|---|
| v-if | 조건 참일 때만 DOM을 생성/파괴 | 낮음 (거짓이면 안 그림) | 높음 (매번 컴포넌트 재생성) | 런타임에 조건이 거의 변하지 않을 때 |
| v-show | 항상 렌더링 후 CSS display 토글 |
높음 (무조건 그림) | 낮음 (단순 CSS 변경) | UI 토글이 매우 빈번하게 발생할 때 |
v-model (양방향 바인딩)
- 장점: 상태(State)와 UI의 동기화를 극도로 간결하게 구현할 수 있어 생산성이 크게 향상되며, 폼(Form) 상태 관리가 직관적이다.
- 단점: 데이터 흐름이 단방향이 아니기 때문에, 컴포넌트 계층이 깊어지면 상태 변경 추적이 어려워질 수 있다. 복잡한 앱의 경우
Vuex,Pinia같은 상태 관리 라이브러리를 활용해 단방향 흐름을 유지하는 것을 권장한다.
안티 패턴: v-if와 v-for를 함께 쓸 때, 불안정한 key
안티 패턴 (Anti-patterns)
v-if와v-for를 같은 element에 사용- 동일한 element에 두 directive를 함께 사용하면 directive priority 때문에
v-ifexpression이v-forscope 변수에 접근하지 못할 수 있다. - Vue 3에서는
v-if가 우선순위가 더 높기 때문에, 아직 순회조차 되지 않은v-for의 내부 변수에v-if가 접근하려 시도하면서 에러가 발생한다. - 해결책:
v-for항목 전체를 감싸는 빈<template>태그를 사용해 분리하거나, 컴포넌트단에서computed속성으로 미리 필터링된 배열을 넘겨주어야 한다.
- 동일한 element에 두 directive를 함께 사용하면 directive priority 때문에
v-for의 불안정한key- 배열 index처럼 항목 identity와 무관한 값을 쓰면 삽입·삭제·정렬 시 기존 DOM/component state가 다른 항목에 재사용될 수 있다.
- Data가 가진 안정적인 unique identifier를
key로 사용한다.
예시
<template>
<div>
<!-- v-bind -->
<a :href="url">링크 바인딩</a>
<!-- v-model -->
<input v-model="message" placeholder="메시지 입력">
<p>{{ message }}</p>
<!-- v-if vs v-show -->
<p v-if="isVisible">렌더링 조건 토글</p>
<p v-show="isVisible">가시성 토글</p>
<!-- v-for -->
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</ul>
<!-- v-on -->
<button @click="handleClick">클릭</button>
</div>
</template>
관련
- Vue.js: 지시어가 속한 프레임워크의 전체 모델이다.
- Vue Reactivity: 반응형 데이터와 Vue 지시어가 상호작용하는 기반 원리다.
- Vue Component Architecture: 지시어는 컴포넌트 template 안에서 Props, events, conditional rendering을 연결한다.
- Browser DOM and Script Loading: "뷰와 모델의 분리" 절이 대비하는
document.getElementById같은 Vanilla JS DOM API가 다루는 DOM 트리와,v-on이 연결하는 native event handler의 맥락을 설명한다.
출처
테스트 질문
- Vue에서
v-if와v-show의 동작 차이와 각 사용이 권장되는 상황은 무엇인가? v-model지시어는 내부적으로 어떻게 동작하며 어떤 편의를 제공하는가?- 동일 엘리먼트에
v-if와v-for를 함께 사용하는 것이 안티 패턴인 이유는 무엇인가?