템플릿 문법(Template Syntax)
템플릿 문법(Template Syntax)
Vue는 HTML 기반의 템플릿 문법을 사용해서, 렌더링된 DOM을 컴포넌트 인스턴스의 데이터에 선언적으로 바인딩할 수 있게 해줘요. 모든 Vue 템플릿은 문법적으로 유효한 HTML이라서 표준을 따르는 브라우저와 HTML 파서가 잘 파싱해요. 텍스트 보간, 속성 바인딩, 디렉티브 문법을 중심으로 정리할게요.
텍스트 보간
데이터 바인딩의 가장 기본은 "Mustache" 문법(이중 중괄호)을 쓰는 텍스트 보간이에요.
<span>Message: {{ msg }}</span>
Mustache 태그는 해당 컴포넌트 인스턴스의 msg 속성 값으로 대체되고, msg가 바뀌면 함께 갱신돼요.
원시 HTML(v-html)
이중 중괄호는 데이터를 평문 텍스트로 해석하지 HTML로 해석하지 않아요. 실제 HTML을 출력하려면 v-html 디렉티브를 써야 해요.
<p>Using text interpolation: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
여기서 보이는 v-html 속성이 바로 디렉티브(directive) 예요. 디렉티브는 v- 접두사로 시작하는 Vue 특별 속성으로, 렌더링된 DOM에 특별한 반응형 동작을 적용해요.
⚠️ 보안 경고: 웹사이트에 임의 HTML을 동적으로 렌더링하는 건 XSS 취약점으로 쉽게 이어질 수 있는 위험한 작업이에요.
v-html은 신뢰할 수 있는 콘텐츠에만, 사용자 제공 콘텐츠에는 절대 쓰면 안 돼요.
속성 바인딩(v-bind)
v-bind 디렉티브는 요소의 id 속성을 컴포넌트의 dynamicId 속성과 동기화하도록 지시해요. 바인딩된 값이 null이나 undefined면 렌더링된 요소에서 해당 속성이 제거돼요.
<div :id="dynamicId"></div>
JavaScript 표현식
템플릿은 단순한 속성 키뿐 아니라 모든 데이터 바인딩에서 JavaScript 표현식의 힘을 지원해요.
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div :id="`list-${id}`"></div>
템플릿 표현식은 샌드박스 처리돼 Math, Date 같은 흔히 쓰는 내장 전역의 제한된 목록만 접근할 수 있어요. window에 붙인 사용자 속성 같은 명시하지 않은 전역은 접근할 수 없어요.
디렉티브
디렉티브는 v- 접두사가 붙은 특별 속성이에요. Vue가 제공하는 내장 디렉티브에는 v-html, v-bind 등이 있어요. 디렉티브 속성 값은 단일 JavaScript 표현식이어야 해요(v-for, v-on, v-slot은 예외). 디렉티브의 일은 표현식 값이 바뀔 때 DOM에 반응형 업데이트를 적용하는 거예요.
v-if를 예로 들면, 표현식 seen의 값의 참/거짓에 따라 <p> 요소를 제거하거나 삽입해요.
<p v-if="seen">Now you see me</p>
인자(Arguments)
v-bind는 :, v-on은 @로 축약할 수 있어요.
<a v-bind:href="url">...</a> <a :href="url">...</a>
<a v-on:click="doSomething">...</a> <a @click="doSomething">...</a>
동적 인자
디렉티브 인자에 JavaScript 표현식을 쓰려면 대괄호로 감싸면 돼요.
<a v-bind:[attributeName]="url">...</a>
<a v-on:[eventName]="doSomething">...</a>
attributeName 값이 "href"면 v-bind:href와 동일해져요.
수식어(Modifiers)
수식어는 점으로 표시되는 디렉티브의 특별한 접미사로, 디렉티브가 어떤 특별한 방식으로 바인딩돼야 하는지 나타내요. 예를 들어 .prevent 수식어는 v-on 디렉티브가 트리거된 이벤트에 event.preventDefault()를 호출하도록 해요.
<form @submit.prevent="onSubmit">...</form>