관리 메뉴

열심히 일한 당신 떠나라

코딩 자율학습단(Vue.js 프런트엔드 개발 입문) 15일차 본문

정보교육/프런트엔드

코딩 자율학습단(Vue.js 프런트엔드 개발 입문) 15일차

@thiskorea 2024. 7. 4. 20:11

9장 Pinia로 상태 관리하기
9.4 실습: Pinia를 사용해 장바구니 앱 만들기

1. 뷰 애플리케이션 초기화

//vue.js.frontend/ch09_cart/src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: HomeView
    },
    {
      path: '/cart',
      name: 'cart',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/CartView.vue')
    }
  ]
})

export default router
// vue.js.frontend/ch09_cart/src/stores/cart.js
import { reactive } from 'vue'
import { defineStore } from 'pinia'

export const useCartStore = defineStore('cart', () => {
  const item = reactive([
    {
      id: 1,
      name: 'banana',
      price: 1000,
    },
    {
      id: 2,
      name: 'orange',
      price: 3000,
    },
    {
      id: 3,
      name: 'mango',
      price: 5000,
    },
    {
      id: 4,
      name: 'apple',
      price: 4000,
    },
  ]);
  const cartItem = reactive([]);  // 장바구니 아이템
  
  return { item, cartItem }
})
// vue.js.frontend/ch09_cart/src/views/CartView.vue
<script setup>

</script>>

<template>
  <h1>장바구니 목록</h1>
</template>
// vue.js.frontend/ch09_cart/src/views/HomeView.vue
<script setup>

</script>>

<template>
  <h1>상품 목록</h1>
</template>
// vue.js.frontend/ch09_cart/src/App.vue
<script setup>
import { RouterLink, RouterView } from 'vue-router'
</script>

<template>
  <RouterView />
</template>
// vue.js.frontend/ch09_cart/src/main.js
// import './assets/main.css'

import { createApp } from 'vue'
import { createPinia } from 'pinia'

import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(createPinia())
app.use(router)

app.mount('#app')

2. 상품 목록 구현하기

// vue.js.frontend/ch09_cart/src/views/HomeView.vue
<script setup>
import { useCartStore } from '@/stores/cart';
import { storeToRefs } from 'pinia';
const cartStore = useCartStore();
// item 비구조화 할당
const { item } = storeToRefs(cartStore);
// 장바구니에 상품 추가 기능, cartItem에 id 추가
const inCart = (id) => {
  cartStore.cartItem.push(id);
};
// 장바구니에 상품 삭제 기능, cartItem에 id 삭제
const outCart = (id) => {
  cartStore.cartItem = cartStore.cartItem.filter((v) => v !== id);
};
</script>>

<template>
  <h1>상품 목록</h1>
  <RouterLink to="/cart">장바구니</RouterLink>
  <ul>
    <li
      v-for="it in item"
      :key="it.id"
      :class="{ in: cartStore.cartItem.includes(it.id)}">
      <span>{{ it.name }}</span>
      <span>{{ it.price }}</span>
      <button
        v-if="!cartStore.cartItem.includes(it.id)"
        @click="inCart(it.id)">담기</button>
      <button v-else @click="outCart(it.id)">삭제</button>
    </li>
  </ul>
</template>

<style scoped>
.in {
  text-decoration: line-through;
}
</style>

3. 장바구니 구현하기

// vue.js.frontend/ch09_cart/src/views/CartView.vue
<script setup>
import { useCartStore } from '@/stores/cart';
import { computed } from 'vue';
const cartStore = useCartStore();
// cartItem에 포함되어 있지 않은 item 값만 필터링
const cartItem = computed(() => {
  return cartStore.item.filter((v) => cartStore.cartItem.includes(v.id));
});
// cartItem 스테이트 값 비우기
const allClear = () => {
  cartStore.cartItem = [];
};
// 장바구니에 담긴 전체 금액을 합산해 alert()으로 보여주기
const payCart = () => {
  const price = cartItem.value.reduce((prev, cur) => {
    return prev + cur.price;
  }, 0);
  alert('총 ${price.toLocaleString()}원을 결제하시겟습니까?');
};
// 장바구니에서 상품 삭제 기능
const outCart = (id) => {
  // cartStore.cartItem = cartStore.cartItem.filter((v) => v !== id); 이 코드는 HomeView와 중복되어 스토어에 보냄.
  cartStore.outCart(id);
};
</script>

<template>
  <h1>장바구니 목록</h1>
  <RouterLink to="/">Home</RouterLink>
  <ul v-if="cartItem.length > 0">
    <li v-for="item in cartItem">
      <span>{{ item.name }}</span>
      <span>{{ item.price }}</span>
      <button @click="outCart(item.id)">삭제</button>
    </li>
  </ul>
  <p v-else>장바구니가 비어 있습니다</p>
  <button @click="payCart">결제</button>
  <button @click="allClear">전체 비우기</button>
</template>