티스토리 뷰

vue의 인스턴스로 구현했던 코드를 Vue.component로 바꾸는 작업을 진행한다.
Components - Intro to Vue.js | Vue Mastery
In this lesson we’ll be learning components: reusable blocks of code that can have both structure and functionality and create a more modular and maintainable codebase.
www.vuemastery.com
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<link rel="stylesheet" type="text/css" href="./style.css">
</head>
<body>
<div class="nav-bar"></div>
<div id="app">
<product></product>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="main.js"></script>
</body>
</html>
Vue.component("product", {
template: `
<div class="product">
<div class="product-image">
<img v-bind:src="image"/>
</div>
<div class="product-info">
<h1>{{ title }}</h1><span v-show="onSale">On Sale!</span>
<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 v-on:click="addToCart"
:disabled="!inStock"
:class="{ disabledButton: !inStock }"
>Add to cart</button>
<div class="cart">
<p>Cart({{ cart }})</p>
</div>
</div>
</div>
`,
data(){
return {
brand: 'Vue Mastery',
product: 'Socks',
selectedVarint: 0,
onSale: false,
details: ["80% cotton", "20% polyester", "Gender-neutral" ],
variants: [
{
variantId: 2234,
variantColor: "green",
variantImage: "./assets/vmSocks-green-onWhite.jpg",
variantQuantity: 10
},
{
variantId: 2235,
variantColor: "blue",
variantImage: "./assets/vmSocks-blue-onWhite.jpg",
variantQuantity: 0
}
],
cart: 0,
}
},
methods: {
addToCart(){
this.cart +=1
},
updateProduct(index){
this.selectedVarint = index
}
},
computed: {
title(){
return `${this.brand} ${this.product}`
},
image(){
return this.variants[this.selectedVarint].variantImage
},
inStock(){
return this.variants[this.selectedVarint].variantQuantity
},
}
})
var app = new Vue({
el: '#app',
})
product 이름을 가진 컴포넌트를 Vue.component로 생성한다.
template에 기존 html 코드를 넣는다. 단, 최상위 요소(root element)는 필수다. 리액트도 최상위 요소 1개는 필수인데 단순하게 묶는 용도라면 Fragment tag(<></>)를 사용하면 편리하다.
data를 JSON 형태가 아닌 메서드 형태로 변경한 후 필요한 데이터를 반환한다.
변경하고 나니 template에 문자열로 되어 있다 보니 가독성이 무척 나빠졌다. 가독성을 높이는 좋은 방법이 있는지 궁금하다.
props를 v-bind 문법으로 전달하는 방법도 소개하고 있다. premium 고객 여부에 따라 배송료 가격을 다르게 노출하는 기능을 추가하면 다음과 같다.
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<link rel="stylesheet" type="text/css" href="./style.css">
</head>
<body>
<div class="nav-bar"></div>
<div id="app">
<product :premium="premium"></product>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="main.js"></script>
</body>
</html>
Vue.component("product", {
props: {
premium: {
type: Boolean,
required: true
}
},
template: `
<div class="product">
<div class="product-image">
<img v-bind:src="image"/>
</div>
<div class="product-info">
<h1>{{ title }}</h1><span v-show="onSale">On Sale!</span>
<p v-if="inStock">In Stock</p>
<p v-else>Out of Stock</p>
<p>Shipping: {{ shipping }}</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 v-on:click="addToCart"
:disabled="!inStock"
:class="{ disabledButton: !inStock }"
>Add to cart</button>
<div class="cart">
<p>Cart({{ cart }})</p>
</div>
</div>
</div>
`,
data(){
return {
brand: 'Vue Mastery',
product: 'Socks',
selectedVarint: 0,
onSale: false,
details: ["80% cotton", "20% polyester", "Gender-neutral" ],
variants: [
{
variantId: 2234,
variantColor: "green",
variantImage: "./assets/vmSocks-green-onWhite.jpg",
variantQuantity: 10
},
{
variantId: 2235,
variantColor: "blue",
variantImage: "./assets/vmSocks-blue-onWhite.jpg",
variantQuantity: 0
}
],
cart: 0,
}
},
methods: {
addToCart(){
this.cart +=1
},
updateProduct(index){
this.selectedVarint = index
}
},
computed: {
title(){
return `${this.brand} ${this.product}`
},
image(){
return this.variants[this.selectedVarint].variantImage
},
inStock(){
return this.variants[this.selectedVarint].variantQuantity
},
shipping(){
if(this.premium){
return "Free"
} else {
return 2.99
}
}
}
})
var app = new Vue({
el: '#app',
data: {
premium: false
}
})
컴포넌트 생성 시 props 옵션 값에 props의 필수 여부와 타입을 지정한다. 리액트에도 같은 기능을 제공하고 있는데 타입 스크립트를 사용하면 타입 체크를 하지 않아도 되기 때문에 타입 스크립트 사용을 추천한다.