오늘은 우리가 만든 Vue 컴포넌트의 화면(HTML)을 동적으로 꾸미는 방법을 배워보겠습니다.
Vue에서는 이 작업을 '템플릿 문법'이라는 특별한 언어를 사용해서 처리합니다.
이번 시간에는 Vue와 소통하기 위한 가장 기본적인 네 가지, {{ }}, v-bind, v-model, v-on에 대해 하나씩 차근차근 알아보겠습니다.
가장 기본이 되는 문법은 이중 중괄호, 일명 '콧수염 괄호'라고 불리는 {{ }} 입니다.
이 괄호는 자바스크립트 세상에 있는 데이터를 HTML 세상으로 가져와 보여주는 역할을 합니다.
마치 이름표에 이름이 들어갈 자리를 {{ 이름 }} 이라고 비워두면, Vue가 실제 이름 데이터를 찾아서 그 자리를 채워주는 것과 같습니다.
이것을
텍스트 보간
이라고 부릅니다.
src/components/Greeting.vue
<template> <!-- script에 있는 message 데이터를 이곳에 보여줍니다. --> <h1>{{ message }}</h1> <p>저의 이름은 {{ user.name }}이고, 나이는 {{ user.age }}살 입니다.</p></template><script setup>import { ref, reactive } from 'vue';// ref는 주로 문자열, 숫자 등 기본형 데이터를 다룰 때 사용합니다.const message = ref('안녕하세요! Vue의 세계에 오신 것을 환영합니다.');// reactive는 주로 여러 정보가 담긴 객체 데이터를 다룰 때 사용합니다.const user = reactive({ name: '김뷰', age: 10});</script>
위 코드에서 {{ message }} 부분은 <script setup> 안에 있는 message 변수의 값인 '안녕하세요! ...' 라는 문자열로 바뀌어 화면에 나타납니다.
user.name과 user.age도 마찬가지로 reactive로 만든 객체의 속성 값으로 바뀝니다.
이 방법은 데이터의 흐름이 자바스크립트에서 HTML로 가는
단방향
입니다.
즉, 데이터가 바뀌면 화면도 바뀌지만, 화면의 내용을 직접 수정한다고 해서 원래 데이터가 바뀌지는 않습니다.
콧수염 괄호 {{ }}는 편리하지만, HTML 태그의 '속성(attribute)' 안에서는 사용할 수 없습니다.
예를 들어, 이미지의 주소를 데이터로 관리하고 싶어서 <img src="{{ imageUrl }}"> 이라고 쓰면 작동하지 않습니다.
이때 사용하는 것이 바로 v-bind 디렉티브입니다.
디렉티브는 v- 접두사가 붙은 특별한 속성으로, Vue에게 "이 속성은 특별하게 처리해 줘!" 라고 알려주는 신호입니다.
src/components/ImageLink.vue
<template> <!-- v-bind를 사용해 이미지 주소를 연결합니다. --> <img v-bind:src="imageUrl" alt="귀여운 강아지"> <!-- v-bind는 자주 사용하기 때문에 단축 문법을 제공합니다. --> <!-- v-bind: 를 생략하고 콜론(:)만 사용해도 똑같이 작동합니다. --> <a :href="linkUrl">네이버로 이동하기</a> <!-- 클래스(class)도 동적으로 제어할 수 있습니다. --> <p :class="{ active: isActive, 'text-danger': hasError }"> 이 글씨는 특정 조건에 따라 스타일이 바뀝니다. </p></template><script setup>import { ref } from 'vue';const imageUrl = ref('https://placedog.net/300/200'); // 이미지 주소 데이터const linkUrl = ref('https://www.naver.com'); // 링크 주소 데이터const isActive = ref(true);const hasError = ref(false);</script><style>.active { color: green; font-weight: bold;}.text-danger { color: red;}</style>
위 예제처럼 v-bind:src 또는 단축 문법인 :src를 사용하면, imageUrl 데이터가 바뀔 때마다 이미지의 src 속성 값이 자동으로 업데이트됩니다.
:class처럼 객체를 사용하면, 특정 데이터(isActive, hasError)가 참(true)일 때만 해당 클래스를 적용하는 등 동적인 스타일링도 쉽게 구현할 수 있습니다.
이제 정말 재미있는 기능인 v-model을 알아볼 차례입니다.
v-bind가 데이터에서 화면으로 가는 단방향 통신이었다면, v-model은 데이터와 화면이 서로를 바라보는
양방향
통신입니다.
사용자가 입력창에 글자를 쓰면(화면의 변화) 자바스크립트 데이터가 즉시 업데이트되고, 자바스크립트 코드에서 데이터를 바꾸면 입력창의 내용(화면)도 즉시 바뀝니다.
주로 <input>, <textarea>, <select> 같은 폼(form) 요소에 사용됩니다.
src/components/InputExample.vue
<template> <!-- input 창에 입력하는 값이 message 데이터와 실시간으로 동기화됩니다. --> <input type="text" v-model="message" placeholder="여기에 입력하세요"> <!-- p 태그는 message 데이터를 보여주기만 합니다. --> <p>입력된 메시지: {{ message }}</p> <button @click="resetMessage">메시지 초기화</button></template><script setup>import { ref } from 'vue';const message = ref(''); // 빈 문자열로 시작function resetMessage() { // 버튼을 누르면 자바스크립트 데이터가 바뀌고, // v-model로 연결된 input 창의 내용도 함께 초기화됩니다. message.value = '초기화되었습니다!';}</script>
이 코드를 실행하고 입력창에 글자를 타이핑해보면, 아래 p 태그의 내용이 실시간으로 따라 변하는 것을 볼 수 있습니다.
반대로 '메시지 초기화' 버튼을 누르면 message 데이터가 바뀌면서 입력창의 내용도 함께 바뀌는 것을 확인할 수 있습니다.
이것이 바로 양방향 데이터 바인딩의 힘입니다.
React를 경험해보신 분이라면 JSX라는 문법에 익숙하실 겁니다.
Vue의 템플릿 문법과 React의 JSX는 화면을 만든다는 점은 같지만, 접근 방식에 차이가 있습니다.
Vue 템플릿:
HTML에 기반을 둡니다.
우리가 아는 순수한 HTML 구조에 v-if, v-for 같은 특별한 속성을 추가하여 동적인 기능을 구현합니다.
자바스크립트 로직은 <script> 태그 안에 명확히 분리되어 있습니다.
HTML에 익숙한 사람이라면 누구나 쉽게 접근할 수 있습니다.
React JSX:
자바스크립트에 기반을 둡니다. HTML처럼 보이는 코드를 자바스크립트 안에 직접 작성합니다.
조건문은 if 대신 && 연산자를 쓰고, 반복문은 .map() 함수를 사용하는 등 모든 것을 자바스크립트 문법으로 처리합니다.
오늘은 Vue 애플리케이션의 화면을 살아 움직이게 만드는 가장 기본적인 템플릿 문법 네 가지를 배웠습니다.
이 네 가지 핵심 문법만 잘 이해하고 있어도 웬만한 동적인 웹 페이지는 충분히 만들 수 있습니다.
이것들은 Vue를 다루기 위한 가장 기본적인 도구들이니, 꼭 손에 익혀두시는 것을 추천합니다.