๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿ’ก์›น ํ”„๋กœ์ ํŠธ/(ํ”„๋ก ํŠธ์—”๋“œ) ๋งˆ์ผ“์ปฌ๋ฆฌ - ํด๋ก ์ฝ”๋”ฉ

vuex ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๊ตฌํ˜„

์ฐธ๊ณ ํ•œ ๊ฒŒ์‹œ๋ฌผ >

https://xn--xy1bk56a.run/vuex/3-cart/#%EC%95%A1%EC%85%98-%EC%B6%94%EA%B0%80

 

1. ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๊ธฐ๋Šฅ ๊ตฌํ˜„

** ์ปดํฌ๋„ŒํŠธ ํด๋” ๊ตฌ์กฐ **

Vuex
(store/index.js)
์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋‹ด๊ธฐ ๋ฒ„ํŠผ๊ณผ ๋ฉ”์„œ๋“œ
(ProductPage.vue)
์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ทฐ
(AddedProductList.vue)

 

** ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๊ด€๋ จ ๋ฒ„ํŠผ ๊ธฐ๋Šฅ **

'+ ๋ฒ„ํŠผ' ํด๋ฆญ์‹œ '- ๋ฒ„ํŠผ' ํด๋ฆญ์‹œ
product์˜ inventory -1
cartItem์˜ quantity +1
cartItem์˜ itemtotalprice + ์ƒํ’ˆ๊ฐ€๊ฒฉ 
product์˜ inventory +1
cartItem์˜ quantity -1
cartItem์˜ itemtotalprice - ์ƒํ’ˆ๊ฐ€๊ฒฉ 
์ดํ•ฉ๊ณ„ = ์นดํŠธ์— ๋‹ด๊ธด ์ƒํ’ˆ์˜ ์ด ๊ฐ€๊ฒฉ

 

1) ์Šคํ† ์–ด์— state, actions, mutations, getters ์ถ”๊ฐ€(store/index.js)

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export const store = new Vuex.Store({
    // ์Šคํ† ์–ด ๊ฐ์ฒด ์˜ต์…˜ ์„ค์ •
    state: {
        products: [
            {
                id: 0,
                title: "๊ฐ•์•„์ง€ ์‚ฌ๋ฃŒ",
                description: "์ˆ˜์ œ ๊ฐ•์•„์ง€ ์‚ฌ๋ฃŒ์ž…๋‹ˆ๋‹ค.",
                price: 15000,
                img: "../assets/images/dogfood.jpg",
                inventory: 10,
            },
            {
                id: 1,
                title: "๊ณ ์–‘์ด ์‚ฌ๋ฃŒ",
                description: "์ˆ˜์ œ ๊ณ ์–‘์ด ์‚ฌ๋ฃŒ์ž…๋‹ˆ๋‹ค.",
                price: 20000,
                img: "../assets/images/dogfood.jpg",
                inventory: 10,
            },
            {
                id: 2,
                title: "์ƒˆ ์‚ฌ๋ฃŒ",
                description: "์ˆ˜์ œ ์ƒˆ ์‚ฌ๋ฃŒ์ž…๋‹ˆ๋‹ค.",
                price: 5000,
                img: "../assets/images/dogfood.jpg",
                inventory: 1,
            },
            {
                id: 3,
                title: "๋ฏธ์–ด์บฃ ์‚ฌ๋ฃŒ",
                description: "์ˆ˜์ œ ๋ฏธ์–ด์บฃ ์‚ฌ๋ฃŒ์ž…๋‹ˆ๋‹ค.",
                price: 25000,
                img: "../assets/images/dogfood.jpg",
                inventory: 2,
            },
            {
                id: 4,
                title: "ํ–„์Šคํ„ฐ ์‚ฌ๋ฃŒ",
                description: "์ˆ˜์ œ ํ–„์Šคํ„ฐ ์‚ฌ๋ฃŒ์ž…๋‹ˆ๋‹ค.",
                price: 10000,
                img: "../assets/images/dogfood.jpg",
                inventory: 30,
            },
            {
                id: 5,
                title: "๊ฑฐ๋ถ์ด ์‚ฌ๋ฃŒ",
                description: "์ˆ˜์ œ ๊ฑฐ๋ถ์ด ์‚ฌ๋ฃŒ์ž…๋‹ˆ๋‹ค.",
                price: 2000,
                img: "../assets/images/dogfood.jpg",
                inventory: 0,
            },
        ],
        cart: [],
    },
   actions: {
        //'+'๋ฒ„ํŠผ ํด๋ฆญ ์‹œ
        addOrder({state, commit}, product) {
        	//์ œํ’ˆ์˜ ๋‚จ์€ ์ˆ˜๋Ÿ‰์ด ์žˆ์„ ๊ฒฝ์šฐ
            if ( product.inventory > 0 ) { 
                const productItem = state.products.find(item => item.id === product.id);
                const cartItem = state.cart.find(item => item.productId === product.id);
                if (!cartItem) {
                    commit('pushProductToCart', productItem); //์ถ”๊ฐ€ํ•  ์ œํ’ˆ์ด ์žฅ๋ฐ”๊ตฌ๋‹ˆ์˜ ์ œํ’ˆ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ, ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์ƒˆ๋กœ ์ถ”๊ฐ€
                } else {
                    if( product.inventory > 0 ) {
                    	commit('incrementItemQuantity', cartItem); //์ผ์น˜ํ•  ๊ฒฝ์šฐ, ์žฅ๋ฐ”๊ตฌ๋‹ˆ์˜ ์ œํ’ˆ ์ˆ˜๋Ÿ‰์„ ์ฆ๊ฐ€}
                    }
                }
                commit('decrementProductInventory', productItem); //๋‚จ์€ ์ˆ˜๋Ÿ‰ -1
                commit('incrementItemTotalPrice', cartItem); //๊ฐ€๊ฒฉ๋ณ€๊ฒฝ
            }
        	//์ œํ’ˆ์˜ ๋‚จ์€ ์ˆ˜๋Ÿ‰์ด ์—†๋Š” ๊ฒฝ์šฐ
            else {
                alert("๋‚จ์€์ˆ˜๋Ÿ‰ ์—†์Œ");
            }
        },
        //'-'๋ฒ„ํŠผ ํด๋ฆญ ์‹œ
        subOrder({state, commit}, product) {
        	//์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด๊ธด ์•„์ดํ…œ์ด ์žˆ์„ ๊ฒฝ์šฐ
            const cartItem = state.cart.find(item => item.productId === product.id);
            if (cartItem.quantity > 0) {
                commit('decrementItemQuantity', cartItem); //์žฅ๋ฐ”๊ตฌ๋‹ˆ์˜ ์ œํ’ˆ ์ˆ˜๋Ÿ‰ -1
                commit('incrementProductInventory', product); //๋‚จ์€ ์ˆ˜๋Ÿ‰ +1
                commit('decrementItemTotalPrice', cartItem); //๊ฐ€๊ฒฉ๋ณ€๊ฒฝ
            }
        	//์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด๊ธด ์•„์ดํ…œ์ด ์—†์„ ๊ฒฝ์šฐ
            else {
                alert("์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด์€ ์ˆ˜๋Ÿ‰ ์—†์Œ");
            }
        }
    },
    mutations: {
        //์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์ œํ’ˆ์„ ์ถ”๊ฐ€
        pushProductToCart(state, product) { 
            state.cart.push({
                productId: product.id,
                title: product.title,
                price: product.price,
                quantity: 1,
                inventory: product.inventory,
                itemtotalprice: product.price,
            });
        },
        //์‡ผํ•‘ ์นดํŠธ์˜ ์•„์ดํ…œ ์ˆ˜๋Ÿ‰ ์ฆ๊ฐ€
        incrementItemQuantity(state, cartItem) { 
            cartItem.quantity++;
        },
        //์‡ผํ•‘ ์นดํŠธ์˜ ์•„์ดํ…œ ์ˆ˜๋Ÿ‰ ๊ฐ์†Œ
        decrementItemQuantity(state, cartItem) { 
            cartItem.quantity--;
        },
        // ์•„์ดํ…œ์˜ ๋‚จ์€ ์ˆ˜๋Ÿ‰ ์ฆ๊ฐ€
        incrementProductInventory(state, product) { 
            product.inventory++;
        },
        // ์•„์ดํ…œ์˜ ๋‚จ์€ ์ˆ˜๋Ÿ‰ ๊ฐ์†Œ
        decrementProductInventory(state, product) { 
            product.inventory--;
        },
        //๊ฐ€๊ฒฉ๋ณ€๊ฒฝ
        incrementItemTotalPrice(state, cartItem) {
            cartItem.itemtotalprice += cartItem.price;
        },
        //๊ฐ€๊ฒฉ๋ณ€๊ฒฝ
        decrementItemTotalPrice(state, cartItem) {
            cartItem.itemtotalprice -= cartItem.price;
        },
    },
    getters: {
        getcartProducts(state) {
            return state.cart.map(cartItem => {
                const product = state.products.find(product => product.id === cartItem.productId);
                if(product === undefined) {
                    return {
                        quantity: 0,
                        itemtotalprice: 0,
                    }
                } else return {
                    id: product.id,
                    title: product.title,
                    price: product.price,
                    inventory: product.inventory,
                    quantity: cartItem.quantity,
                    itemtotalprice: cartItem.itemtotalprice,
                };
            });
        },
        getcartProductsthis:(state) => (productItem) => {
            const cartItem = state.cart.find(item => item.productId === productItem.id);
            const product = state.products.find(product => product.id === productItem.id);
            if(cartItem === undefined) {
                return {
                    quantity: 0,
                    itemtotalprice: 0,
                }
            }
            return {
                product : product.title,
                quantity: cartItem.quantity,
                itemtotalprice: cartItem.itemtotalprice,
            };
        },
        cartTotal(state) {
            let total = 0;
            state.cart.forEach(cartItem => {
                total += cartItem.itemtotalprice;
            });
            return total;
        },
    },
})

 

2) ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋‹ด๊ธฐ ๋ฒ„ํŠผ๊ณผ ๋ฉ”์„œ๋“œ(ProductPage.vue)

<template>
  <div id="productpage">
    <div id="productsimple">
      <div class="product-img">
        <img src="../assets/images/dogfood.jpg" alt />
      </div>
      <div class="product-simpleinfo">
        <ul>
          <li class="title" v-text="product.title"></li>
          <li class="des" v-text="product.description"></li>
          <li class="price">{{ product.price }}์›</li>
        </ul>
        <div>๋‚จ์€ ์ˆ˜๋Ÿ‰ : {{ product.inventory }}๊ฐœ</div>
        <div id="editquantity">
          <button @click="subOrder(product)">-</button>
          <div>
            {{ $store.getters.getcartProductsthis(product).quantity }}
          </div>
          <button @click="addOrder(product)">+</button>
        </div>
        <div class="total">
        	์ดํ•ฉ๊ณ„ : {{ $store.getters.getcartProductsthis(product).itemtotalprice }}์›
        </div>
      </div>
    </div>

    <div id="productdetail"></div>
  </div>
</template>

<script>
export default {
  name: "ProductPage",
  data() {
    const index = this.$route.params.contentId;
    return {
      product: this.$store.state.products[index]
    };
  },
  methods: {
    addOrder(product) {
      this.$store.dispatch("addOrder", product);
    },
    subOrder(product) {
      this.$store.dispatch("subOrder", product);
    },
  },
};
</script>

 

3) ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ทฐ(AddedProductList.vue)

<template>
  <div id="addedproductlist">
    <div>
      <div>
        <div
          v-if="$store.getters.getcartProducts.length === 0"
          class="shopped-item"
        >
          ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด์€ ์ƒํ’ˆ์ด ์—†์Šต๋‹ˆ๋‹ค.
        </div>
        <div
          v-else
          class="shopped-item"
          :key="index"
          v-for="(cartproduct, index) in $store.getters.getcartProducts"
        >
          <div class="shopped-imgtitle">
            <img src="../assets/images/dogfood.jpg" />
            <div class="shopped-title">{{ cartproduct.title }}</div>
          </div>
          <div id="editquantity">
            <button @click="subOrder(cartproduct)">-</button>
            <div>
              {{ cartproduct.quantity }}
            </div>
            <button @click="addOrder(cartproduct)">+</button>
          </div>
          <div class="shopped-price">
            {{ cartproduct.itemtotalprice }}์›
          </div>
        </div>
        <div class="shopped-total">
          ์ด ๊ฐ€๊ฒฉ :  {{ $store.getters.cartTotal }}์›
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "AddedProductList",
  methods: {
    addOrder(cartproduct) {
      this.$store.dispatch("addOrder", cartproduct);
    },
    subOrder(cartproduct) {
      this.$store.dispatch("subOrder", cartproduct);
    }
  },
};
</script>

 

2. ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ

1) ProductPage.vue

  • +-๋ฒ„ํŠผ ํด๋ฆญ ์ „
  • +-๋ฒ„ํŠผ ํด๋ฆญํ•œ ํ›„

2) AddedProductList.vue

์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์žˆ๋Š” ์นดํŠธ๋ชฉ๋ก์„ ๋ณด๋ฉด ๋‹ด๊ธด ์ƒํ’ˆ๋“ค์„ ํ™•์ธํ•˜๊ฑฐ๋‚˜ ์ƒํ’ˆ ๊ฐœ์ˆ˜๋ฅผ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ๋‹ค!