* 이 글은 SFC(싱글 파일 컴포넌트) 문법을 사용합니다.
싱글 파일 컴포넌트의 <script>
태그 안에는 다양한 속성이 있을 수 있으며, 이러한 속성들을 활용해 Vue 컴포넌트를 정의하고 데이터와 로직을 관리할 수 있다.
그 중 가장 일반적으로 사용되는 다음 다섯 가지의 주요 속성에 대해 알아보자.
components
: 다른 Vue 컴포넌트를 해당 컴포넌트 내에서 사용할 때 등록하는 속성props
: 부모 컴포넌트로부터 데이터를 받아오는 속성data()
: 컴포넌트 내에서 사용할 데이터를 정의하는 속성methods
: 컴포넌트 내에서 사용할 메소드(함수)를 정의하는 속성computed
: data, props를 기반으로 계산된 값을 반환하는 속성: Vue 컴포넌트 내에서 다른 Vue 컴포넌트를 사용하는 데 사용되는 속성
아래와 같이 ButtonCounter 라는 컴포넌트가 있다.
// ButtonCounter.vue
<template>
<button @click="count++">당신은 {{ count }} 번 클릭했습니다.</button>
</template>
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>
<style>
</style>
이 컴포넌트를 부모 컴포넌트에서 사용하고 싶다면,
<script>
태그 안에서 해당 컴포넌트를 import하고,components
옵션을 사용해서 등록해야 한다.컴포넌트 이름 표기법은 PascalCase를 사용해도 되고, kebab-case를 사용해도 된다.
// App.vue
<template>
<h1>아래에 자식 컴포넌트가 있습니다.</h1>
<ButtonCounter /> // PascalCase
<button-counter /> // kebab-case
</template>
<script>
import ButtonCounter from './ButtonCounter.vue' // 컴포넌트 import
export default {
components: {
ButtonCounter // 등록
// 'my-button-counter': ButtonCounter 👈 케밥 케이스 & 컴포넌트명 변경 가능
}
}
</script>
<style>
</style>
: 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 사용하는 속성
만약 <Blog>
라는 부모 컴포넌트에서 <BlogPost>
라는 자식 컴포넌트로 id
와 title
를 props를 전달해주어 <BlogPost>
를 렌더링한다고 가정해보면 아래와 같이 작성할 수 있다.
// Blog.vue
<template>
<blog-post id="1" title="Vue와 함께한 나의 여행" /> // 자식 컴포넌트
</template>
<script>
import BlogPost from './BlogPost.vue'
export default {
components: {
'blog-post': BlogPost,
}
}
</script>
<style>
</style>
자식 컴포넌트에서 전달받은 props를 사용하려면 props
속성 내에 전달받으려는 props를 프로퍼티 이름: 데이터 타입
형식으로 정의해야 한다.
this
컨택스트에서 접근할 수도 있다. (this.id
, this.title
로 접근 가능)// BlogPost.vue
<template>
<h4>{{ title }}</h4> // 템플릿 내에서 사용
</template>
<script>
export default {
props: {
// 프로퍼티 이름: 데이터 타입
id: Number,
title: String,
}
}
</script>
<style>
</style>
<script>
export default {
props: {
id: { type: Number, required: true }, // 유효성 검사
title: { type: String, default: '무제' }, // 기본값
}
}
</script>
하지만 보통은 위의 예시처럼 id
와 title
을 하드코딩해서 전달해주기 보다 부모 컴포넌트에 있는 데이터를 동적으로 전달해주는 경우가 많다.
부모 컴포넌트에 아래와 같은 배열이 있고, <BlogPost>
컴포넌트를 여러 개 렌더링해야 한다면 어떻게 해야할까?
posts: [
{ id: 1, title: 'Vue와 함께한 나의 여행' },
{ id: 2, title: 'Vue로 블로깅하기' },
{ id: 3, title: 'Vue가 재미있는 이유' }
// ...(200개)
]
리액트에서는 map()
메소드를 사용하지만, 뷰에서는 v-for
디렉티브를 사용한다.
v-for
: Vue.js에서 반복문을 처리하고 템플릿(HTML)을 렌더링하는 데 사용되는 디렉티브
<ul> <li v-for="(item, index) in items" key="item.id">{{ index }}. {{ item }}</li> </ul>
map()
메소드를 사용할 때와 마찬가지로v-for
디렉티브를 사용할 때는 Vue.js가 렌더링되는 각 요소(list item)들을 구별하고 어떤 요소가 변경되었는지 확인하여 효율적으로 렌더링을 수행할 수 있도록 고유한key
속성을 지정해줘야 한다.
v-bind
: Vue 데이터와 HTML 요소의 속성/프로퍼티를 동적으로 연결(binding)하는 디렉티브
데이터가 변경되면 화면이 동적으로 업데이트되도록 해준다.<button :disabled="isButtonDisabled">버튼</button>
// Blog.vue
<template>
<div>
<h1>블로그 포스트</h1>
<BlogPost
v-for="post in posts"
:key="post.id"
:post="post" // v-bind의 단축 문법 (:)
/>
</div>
</template>
<script>
import BlogPost from './BlogPost.vue';
export default {
data() {
return {
posts: [
{ id: 1, title: 'Vue와 함께한 나의 여행' },
{ id: 2, title: 'Vue로 블로깅하기' },
{ id: 3, title: 'Vue가 재미있는 이유' }
]
};
},
components: {
'blog-post': BlogPost,
}
};
</script>
그리고 자식 컴포넌트에서는 post
자체를 객체로 받아와 사용할 수도 있다.
// BlogPost.vue
<template>
<div>
<h2>{{ post.title }}</h2>
</div>
</template>
<script>
export default {
props: {
post: { type: Object, required: true }
}
};
</script>