쇼핑 카트 뷰

쇼핑 카트의 기능은 구현되었지만, 사용자에게 쇼핑 카트 뷰(View)를 제공해야 합니다. 쇼핑 카트 컴포넌트를 만들어 UI를 구현해봅니다.

ShoppingCart 컴포넌트

ShoppingCart 컴포넌트 파일을 만든 후 템플릿 코드를 작성합니다.












 
 
 
 
 


 




<!-- components/ShoppingCart.vue -->

<div class="shopping-cart">
  <h1>장바구니</h1>
  <table>
    <caption>장바구니에 담긴 도서</caption>
    <tr>
      <th>제목</th>
      <th>가격</th>
      <th>수량</th>
    </tr>
    <tr v-for="book in books" :key="book.id">
      <td>{{ book.name }}</td>
      <td>{{ book.price }}</td>
      <td>{{ book.quantity }}</td>
    </tr>
    <tr>
      <th>총계</th>
      <td colspan="2">{{ total }}</td>
    </tr>
  </table>
</div>

NOTE

사용자가 쇼핑 카트에 추가한 도서 book 데이터의 모형은 다음과 같습니다.

book = { name, price, quantity }

컴포넌트 계산된 속성 books, total을 추가한 후 스토어의 게터로부터 계산된 값을 가져오는 코드를 작성합니다.






 
 

 
 




// components/ShoppingCart.vue

export default {
  name: 'ShoppingCart',
  computend: {
    books() {
      return this.$store.getters.cartBooks;
    },
    total() {
      return this.$store.getters.cartTotal;
    }
  }
}

App.vue에서 ShoppingCart.vue를 불러와 쇼핑 카트를 화면에 렌더링 하는 코드를 작성합니다.







 





 





 




// App.vue

<template>
  <div id="app">
    <BookList/>
    <hr>
    <ShoppingCart/>
  </div>
</template>

<script>
import BookList from "./components/BookList.vue";
import ShoppingCart from "./components/ShoppingCart.vue";

export default {
  name: "app",
  components: {
    BookList,
    ShoppingCart
  }
};
</script>

cartBooks, cartTotal 게터

컴포넌트가 요구하는 계산된 값을 제공하기 위해 스토어에 cartBooks, cartTotal 게터를 추가합니다.




 
 
 
 
 
 
 
 
 

 
 
 
 
 
 



// store/index.js

getters: {
  cartBooks(state) {
    return state.cart.map(cartItem => {
      const book = state.books.find(book => book.id === cartItem.id);
      return {
        id: book.id,
        price: book.price,
        quantity: cartItem.quantity
      };
    });
  },
  cartTotal(state, getters) {
    let total = 0;
    getters.cartBoooks.forEach(cartItem => {
      total += cartItem.price * cartItem.quantity;
    });
    return total;
  }
}

NOTE

배열 객체의 reduce 메서드를 사용해 cartTotal 게터를 작성할 수도 있습니다.


 


cartTotal(state, getters) {
  return getters.cartBoooks.reduce((total,cartItem) => total + cartItem.price * cartItem.quantity, 0);
}

원화 필터

도서의 가격(숫자)을 원화로 필터링 하는 필터를 정의합니다.

// filters/won.js

export default function won(value) {
  return
    `${String(value)
      .split('')
      .reverse()
      .map((c,i) => ((i > 0 && i % 3 === 0) ? c + ',' : c))
      .reverse()
      .join('')} 원`;
}

모든 컴포넌트에서 원화 필터를 사용할 수 있도록 글로벌 필터로 등록합니다.

// main.js

import won from './filters/won';

Vue.filter('won', won);

BookList, ShoppingCart 컴포넌트에 원화 필터를 사용합니다.








 








<!-- components/BookList.vue -->

<div class="book-list">
  <h1>도서 목록</h1>
  <img v-if="loading" src="https://i.imgur.com/JfPpwOA.gif" alt="로딩 중...">
  <ul v-else>
    <li v-for="(book,i) in books" :key="i">
      {{ book.name }} / {{ book.price | won }}
      <button
        type="button"
        @click="addBookToCart(book)"
      >카트에 추가</button>
    </li>
  </ul>
</div>














 




 





<!-- components/ShoppingCart.vue -->

<template>
  <div class="shopping-cart">
    <h1>장바구니</h1>
    <table border="1" v-if="books.length">
      <caption>장바구니에 담긴 도서</caption>
      <tr>
        <th>제목</th>
        <th>가격</th>
        <th>수량</th>
      </tr>
      <tr v-for="book in books" :key="book.id">
        <td>{{ book.name }}</td>
        <td>{{ book.price | won }}</td>
        <td>{{ book.quantity }}</td>
      </tr>
      <tr>
        <th>총계</th>
        <td colspan="2">{{total | won}}</td>
      </tr>
    </table>
  </div>
</template>