지금부터 Vue.js의 중요한 요소 중 하나인 컴포넌트에 대해 알아보도록 합시다. 처음이니만큼 기초에 대해 배우며, 더욱 자세한 사항은 공식 문서를 참고해주시기 바랍니다.
<template>
<MyBtn /> // 컴포넌트 렌더링
</template>
<script>
import MyBtn from '~/components/MyBtn' // MyBtn.vue 파일 가져오기
export default {
components: {
MyBtn // 가져온 컴포넌트 내부에서 사용할 수 있도록 내보내기
}
}
</script>
<template>
<div class="btn">
Apple
</div>
</template>
<style scoped>
.btn {
display: inline-block;
margin: 4px;
padding: 6px 12px;
border-radius: 4px;
background-color: gray;
color: white;
cursor: pointer;
}
</style>
<template>
<MyBtn />
<MyBtn />
<MyBtn />
</template>
컴포넌트의 장점이라고 한다면, 컴포넌트는 얼마든지 반복해서 재사용할 수 있다는 것입니다. App.vue
파일에 위와 같이 작성한다면 버튼을 재활용하여 여러 개를 화면에 출력할 수 있기 때문입니다.
또한, 이렇게 재활용을 하면서 props
라는 개념을 이용하여 App.vue
라는 부모 컴포넌트에서 MyBtn.vue
라는 자식 컴포넌트로 데이터를 전달할 수 있습니다.
이러한 이유로 props
를 통해 구현한 이 기능을 부모 컴포넌트와 자식 컴포넌트 간의 데이터 통신 방법이라고도 이야기합니다.
App.vue
<MyBtn color="royalblue" />
MyBtn.vue
<div :style="{ backgroundColor: color }" class="btn"> // 데이터 바인딩 Apple </div>
export default { props: { color: { // 외부에서 color 값을 지정할 때 받을 수 있게 함 type: String, default: 'gray' // 기본값 지정 } } }
이번에는 props
를 이용해 클래스를 추가해보도록 합시다.
App.vue
<!-- <div class ="large btn"> --> <MyBtn large /> <!-- <div class ="btn"> --> <MyBtn large />
부모 컴포넌트에는
large
라는 속성을 별도의 값이 없도록 추가해줍니다.MyBtn.vue
<div :class="{ large }" class="btn"> Apple </div>
export default { props: { large: { type: Boolean, default: false } } }
위와 같이 props
에 속성 large
객체 리터럴 안으로 type
으로 불린 데이터를 지정하고, default
값으로 large
라는 속성이 없도록 false
를 지정해줍니다.
그러면 위처럼 클래스에 large
가 추가되어있고, 그렇지 않은 버튼은 포함되어 있지 않은 것을 확인할 수 있습니다.
props
를 이용하면 text의 내용 또한 입력이 가능합니다.
App.vue
<MyBtn text="Banana" /> <MyBtn :color="color" /> <MyBtn large color="royalblue" /> <MyBtn />
MyBtn.vue
<div class="btn"> {{ text }} </div>
export default { props: { text: { type: String, default: '' // 기본값은 공백 } } }
위처럼 MyBtn의 text
속성에 추가한 값이 버튼 안의 내용으로 입력되게 됩니다. 하지만 이를 화면에 출력하게 되면, 문제점을 발견하게 됩니다.
바로 위와 같이 text
속성을 추가하지 않은 개체는 컨텐츠 내용이 출력되지 않게 됩니다. 당연하게도 Vue.js에서는 해결 방법을 제공하며, slot
이라는 개념입니다.
text
를 속성으로 넣게 되면, 위와 같은 문제가 발생하였습니다. 그렇다면 이를 해결하기 위해 html에서 <button>text<button>
처럼 컨텐츠 내용으로 직접 텍스트를 입력하는 방법을 활용해보도록 합시다.
App.vue
<MyBtn>Banana</MyBtn> <MyBtn :color="color">Apple</MyBtn> <MyBtn large color="royalblue">Cherry</MyBtn> <MyBtn>Orange</MyBtn>
이처럼 부모 컴포넌트에 빈 태그가 아닌 열리고 닫히는 태그의 형태로 표시해줍니다. 그리고 그 안에는 컨텐츠로 들어가는 내용을 입력해줍니다.
MyBtn.vue
<div class="btn"> <slot></slot> // 컨텐츠 자리 표시 </div>
// 내용 삭제 // export default { // props: { // text: { // type: String, // default: '' // } // } // }
그리고 버튼 안에 입력할 컨텐츠의 자리를 표시를 해줘야하겠죠? 이 때 바로 slot
태그를 사용합니다. 그렇다면, 이제 위처럼 props
에 입력했던 text
내용은 필요가 없으니 삭제해버립니다.
App.vue
<MyBtn :color="color"> <span style="color: red">Banana</span> </MyBtn>
덧붙여, slot
태그에는 단순히 text만 입력하는 것이 아니라 자식 컴포넌트가 실행되는 부분에서 열리고 닫히는 태그 사이에 있는 모든 내용을 slot
이라는 태그 부분으로 대체하여 넣어준다는 개념입니다. 이를 통해 위처럼 span
태그 안에 text를 입력하고, 스타일까지 적용을 할 수가 있는 것입니다.
위처럼 아주 잘 출력이 됩니다 :D