vue component 란
컴포넌트란 재사용가능한 코드 조각이며 SPA 프레임워크로 웹을 개발하게 되면 페이지 단위가 아니라 많은 컴포넌트들이 모여서 하나의 페이지를 만들게 되며 컴포넌트가 개발의 중심이 되게 된다.
기초가 되는 자바스크립트 문법은 es5의 생성자 함수와 es6 의 클래스이다.
컴포넌트를 정의하는 문법은 Vue Instance와 거의 유사하나 몇가지에서 약간 다르다. Vue.component(‘이름’, { options })
options에는 Vue instance와 같은 option이 들어갈 수 있는데, DOM에 렌더링 되는것이 아니라 부모 컴포넌트에 포함되므로 자기 자신의 template을 가지게 된다. template은 view를 구성하게 되고 반드시 하나의 엘리먼트만 가져야 된다.
그리고, data는 속성이 아니라 function 이어야 한다. 그 이유는 속성일 경우 같은 속성값을 공유 하므로 컴포넌트마다 다른 속성값을 가지기 위해서 function이 되어야 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Vue.component('product', { template: ` <div> ... </div> `, data() { return { ... } }, computed: { ... }, methods: { ... } }); |
기존 코드에서 작성한 Vue Instance를 Vue Component로 바꾸어 보자.
먼저, Vue.component에 이름과 options을 선언한다.
html의 template을 가져와서 option 에 template의 backtick으로 가져온다.
기존 vue instance의 data, computed, methods를 그대로 가져오대 data를 속성에서 function으로 바꾼다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
Vue.component('product', { template: ` <div class="product"> <div class="product-image"> <img :src="image"> </div> <div class="product-info"> <h1>{{title}}</h1> <p v-if="inStock">In Stock</p> <p v-else="">Out of Stock</p> <ul> <li v-for="detail in details">{{ detail }}</li> </ul> <div class="color-box" v-for="(variant, index) in variants" :key="variant.variantId" :style="{ backgroundColor: variant.variantColor }" @mouseover="updateProduct(index)"> </div> <button @click="addToCart" :disabled="!inStock" :class="{ disabledButton: !inStock }">Add to cart</button> <div class="cart"> <p>Cart({{ cart }})</p> </div> </div> </div> `, data() { return { product: 'Socks', brand: 'Vue Mastery', details: ['80% cotton', '20% polyester', 'Gender-neutral'], selectedVariant: 0, variants: [ { variantId: 2234, variantColor: 'green', variantImage: 'https://www.vuemastery.com/images/challenges/vmSocks-green-onWhite.jpg', variantQuantity: 10 }, { variantId: 2235, variantColor: 'blue', variantImage: 'https://www.vuemastery.com/images/challenges/vmSocks-blue-onWhite.jpg', variantQuantity: 0 } ], cart: 0 } }, computed: { title() { return this.brand + ' ' + this.product; }, image() { return this.variants[this.selectedVariant].variantImage; }, inStock() { return this.variants[this.selectedVariant].variantQuantity; } }, methods: { addToCart() { this.cart += 1 }, updateProduct(index) { this.selectedVariant = index; } } }); var app = new Vue({ el: '#app', }); |
html에는 root DOM에 product 컴포넌트를 넣는다.
1 2 3 4 5 |
... <div id="app"> <product></product> </div> ... |
테스트해보자. 화면은 동일하게 나와야 한다.
<product> 라는 노드는 html 엘리먼트가 아니므로 vue 컴포넌트로 해석하게 된다.
부모 => 자식간의 통신
이제 웹앱 개발은 페이지 단위가 아니라 수많은 레고 블락같은 컴포넌트가 모여서 이루어진 집합체가 될것이다. 그러면 이제 수많은 컴포넌트들끼리 통신을 어떻게 해야 할건지가 중요해진다.
컴포넌트를 거대한 트리 구조를 이루게 되는데, 자식 컴포넌트가 부모 컴포넌트에 접근할 수는 없고 부모 컴포넌트가 자식컴포넌트에게 props라는 속성을 물려줄 수 있다.
- 부모컴포넌트
1 |
<product :num="5"></product> |
- 자식컴포넌트
1 2 3 4 5 6 7 8 9 10 11 |
props: ['num'] or props: { num: { type: String, required: true, default: "1" } } |
부모 뷰 인스턴스에 premium 속성을 추가한다.
1 2 3 4 5 6 |
var app = new Vue({ el: '#app', data: { premium: true } }); |
자식컴포넌트에게 premium 속성으로 해당 값을 내려준다.
1 2 3 4 5 |
... <div id="app"> <product :premium="premium"></product> </div> ... |
자식 컴포넌트에서 props로 해당 값을 정의하고 태그를 추가한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
... <div class="product-info"> <h1>{{title}}</h1> <p v-if="inStock">In Stock</p> <p v-else>Out of Stock</p> <p>User is premium: {{premium}}</p> ... props: { premium: { type: Boolean, required: true, } }, ... |
+ todo
ul – li 에 detail로 보여주는 부분을 컴포넌트화 한다.
1) product-details 라는 이름의 컴포넌트를 선언한다.
ul – li 부분을 떼어내서 새로만든 컴포넌트의 template에 넣는다.
ul – li를 떼어낸 자리에는 <product-details>로 대체한다.
2) product-details 컴포넌트에 details props를 전달한다.
<product-details> 에 details 속성으로 details 를 넘겨준다.
자식인 product-details 컴포넌트에 props로 details 속성을 받는다. 타입은 Array , required는 true로 선언한다.
See the Pen Challenge 8 – Intro to Vue by Gregg Pollack (@GreggPollack) on CodePen.0