티스토리 뷰

728x90

 

cart html를 상위 컴포넌트로 이동시킨 후 하위 컴포넌트(product)에서 add to cart 버튼이 클릭됐을 때 장바구니 상태를 업데이트하도록 변경한다.

<!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">
            <div class="cart">
                <p>Cart({{ cart.length }})</p>
            </div>
            <product :premium="premium" @add-to-cart="addToCart"></product>
        </div>

        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script src="main.js"></script>
    </body>
</html>

emit를 사용하면 광범위하게 이벤트가 전파 되기때문에 선호하지 않는 방법을 사용하고 있다. 🤔

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>
    </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.$emit("add-to-cart", this.variants[this.selectedVarint].variantId)
        },
        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,
        cart: []
    },
    methods: {
        addToCart(id){
            this.cart.push(id)
        }
    }
})

리액트의 경우 상위 컴포넌트에서 작성한 함수를 자식 컴포넌트의 props로 넘겨줄 수 있다. 이벤트 전달 방식이 리액트와 무척 다른 점이다. 더 나은 방법이 있길...

728x90
댓글