Byte Ebi's Logo

Byte Ebi 🍤

每天一小口,蝦米變鯨魚

[Express+Vue 搭建電商網站] 14 使用組件思維重構頁面邏輯

使用 Express + Vue 搭建一個電商網站 - 使用組件思維重構頁面邏輯

Ray

在先前我們學會怎麼使用 Vuex 進行狀態管理、如何使用 Action 取得 API 資料,以及使用 Mutation 更改狀態
而這一篇中將透過 Vue 的組件化思維簡化原本複雜且分散於各個頁面的邏輯

建立 ProductButton 組件

新建一個 src/components/products/ProductButton.vue 檔案
準備用這個組件替換掉操作購物車中狀態按鈕的組件

<template>
  <div>
    <button v-if="isAdding" class="button" @click="addToCart">加入購物車</button>
    <button v-else class="button" @click="removeFromCart(product._id)">從購物車移除</button>
  </div>
</template>

<script>
export default {
  props: ["product"],
  computed: {
    isAdding() {
      let isAdding = true;
      this.cart.map(product => {
        if (product._id === this.product._id) {
          isAdding = false;
        }
      });

      return isAdding;
    },
    cart() {
      return this.$store.state.cart;
    }
  },
  methods: {
    addToCart() {
      this.$store.commit("ADD_TO_CART", {
        product: this.product
      });
    },
    removeFromCart(productId) {
      this.$store.commit("REMOVE_FROM_CART", {
        productId
      });
    }
  }
};
</script>

在這個組件中,透過了 v-if 來判斷 isAdding 這個 computed 是否為真
isAdding 使用了來自 Vuex store 中 state 的 cart 參數
藉由遍歷整個 cart 判斷當前的商品是否在購物車內,進而顯示對應的按鈕,並綁定不同的行為
addToCartremoveFromCart 這兩個方法會調用 mutation 而改變 Vuex store 中的狀態

建立 ProductItem 組件

建立好了按鈕後,要建立個別商品在渲染時使用的組件
建立 src/components/products/ProductItem.vue 顯示商品相關資訊
並引入上一步建立的 ProductButton 組件

<template>
  <div>
    <div class="product">
      <p class="product__name">商品名稱{{product.name}}</p>
      <p class="product__description">簡介{{product.description}}</p>
      <p class="product__price">售價{{product.price}}</p>
      <p class="product.manufacturer">生產商{{product.manufacturer.name}}</p>
      <img :src="product.image" alt class="product__image" />
      <product-button :product="product"></product-button>
    </div>
  </div>
</template>

<script>
import ProductButton from "./ProductButton";
export default {
  name: "product-item",
  props: ["product"],
  components: {
    "product-button": ProductButton
  }
};
</script>

透過 import ProductButton from "./ProductButton" 引入剛剛建立的 ProductButton 組件
並註冊在 components 物件中,最後在模板中使用組件

重構 ProductList 組件

接著就可以把 src/components/products/ProductList.vue 這個組件重構
把跟商品相關的模板部分移除,methods 中的加入購物車方法也一併移除
因為單一商品的資料以及按鈕都已經加入到剛剛的 ProductItem 組件中

<template>
  <div>
    <div class="products">
      <div class="container">This is ProductList</div>
      <template v-for="product in products">
        <product-item :product="product" :key="product._id"></product-item>
      </template>
    </div>
  </div>
</template>

<style>
.product {
  border-bottom: 1px solid black;
}

.product__image {
  width: 100px;
  height: 100px;
}
</style>

<script>
import ProductItem from './ProductItem.vue';
export default {
  name: "product-list",
  created() {
    if (this.products.length === 0) {
      this.$store.dispatch("allProducts");
    }
  },
  computed: {
    // a computed getter
    products() {
      return this.$store.state.products;
    }
  },
  components: {
    'product-item': ProductItem
  },
};
</script>

我們在引用了 ProductItem 組件後,利用 v-for 把每個商品都傳入組件用來建立商品列表

重構 Cart 頁面

就跟在 ProductItem 組件中一樣,我們也將 src/views/Cart.vue 頁面中的商品列表組件化

<template>
  <div>
    <div class="title">
      <h1>{{msg}}</h1>
    </div>
    <template v-for="product in cart">
      <product-item :product="product" :key="product._id"></product-item>
    </template>
  </div>
</template>

<style>
.product {
  border-bottom: 1px solid black;
}

.product__image {
  width: 100px;
  height: 100px;
}
</style>

<script>
import ProductItem from "@/components/products/ProductItem.vue";
export default {
  name: "home",
  data() {
    return {
      msg: "Welcome to the Cart Page"
    };
  },
  computed: {
    cart() {
      return this.$store.state.cart;
    }
  },
  components: {
    "product-item": ProductItem
  }
};
</script>

一樣引入 ProductItem 組件,並且在 components 中註冊
接著就可以在模板中把購物車內的商品傳入給組件使用
而頁面的功能不會有所改變,只是把重複的部分整合成組件來共用,增加維護性


專案範例程式碼 GitHub 網址:ray247k/mini-E-commerce

最新文章

Category

Tag