[Express+Vue 搭建電商網站] 14 使用組件思維重構頁面邏輯
使用 Express + Vue 搭建一個電商網站 - 使用組件思維重構頁面邏輯
在先前我們學會怎麼使用 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
判斷當前的商品是否在購物車內,進而顯示對應的按鈕,並綁定不同的行為
addToCart
和 removeFromCart
這兩個方法會調用 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