Shopping cart
项目概述
从运行的截图上,不难看出是一个简单的商品购物的页面。products应该是从vuex中获得所有的商品数据。商品有一定的库存量,每次加入购物车一次,就会减少一个,只到为0的时候就不可以购买。your cart是购物车,每次点击购买的时候,购物车里会增加一个商品。同时会增加一件商品进入购物车,购物车有金额的汇总。然后点击结账,会偶尔成功,偶尔失败。
揣测程序的实现思路
个人认为在写代码本身是在解决问题。阅读代码是为了理解别人解决问题的思路。那么在阅读之前,最好是能自己想想,如果自己写这个代码,会如何写。然后再对照别人的代码,这样才能深入学习。
个人思路
可以建立两个Modules,一个存放products,一个存放shopping carts。
存放products的Module,在state中需要保存所有的商品数据,然后mutations中需要有一个addToCart的方法。还要有一个getters,需要获得所有的products。addTOCart负责减少仓库中商品的数量。而获得所有商品的getters需要获得所有仓库中的商品信息。
存放your cart的需要在state中存放所有的购物车数据,以及汇总金额,Mutations中需要有addToCart方法,来增加商品。Checkout负责清空所有的购物车。最好还要有一个getters来计算所有商品的价格。
然后页面上可以建立两个组件,一个商品列表,一个购物车。
项目的目录结构
项目实现
API 部分
const _products = [
{
'id': 1, 'title': 'iPad 4 Mini', 'price': 500.01, 'inventory': 2 },
{
'id': 2, 'title': 'H&M T-Shirt White', 'price': 10.99, 'inventory': 10 },
{
'id': 3, 'title': 'Charli XCX - Sucker CD', 'price': 19.99, 'inventory': 5 }
]
export default {
getProducts (cb) {
setTimeout(() => cb(_products), 100)
},
buyProducts (products, cb, errorCb) {
setTimeout(() => {
// simulate random checkout failure.
(Math.random() > 0.5 || navigator.webdriver)
? cb()
: errorCb()
}, 100)
}
}
这部分是我们思路中没有的,项目中思考更加全面和完善mock了服务器端。做了两个函数一个获得产品信息,一个递交购物车信息。然后用了回调函数来把从服务器端获得信息发送回去state中去。
products.js
import shop from '../../api/shop'
// initial state
const state = () => ({
all: []
})
// getters
const getters = {
}
// actions
const actions = {
getAllProducts ({
commit }) {
shop.getProducts(products => {
commit('setProducts', products)
})
}
}
// mutations
const mutations = {
setProducts (state, products) {
state.all = products
},
decrementProductInventory (state, {
id }) {
const product = state.all.find(product => product.id === id)
product.inventory--
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
比我们思路上增加一个action,用来调用获得所有的商品,并且commit到设置商品中去,当然也多了一个初始化商品数据的方法。另外没设置获得所有商品的方法。
cart.js
import shop from '../../api/shop'
// initial state
// shape: [{ id, quantity }]
const state = () => ({
items: [],
checkoutStatus: null
})
// getters
const getters = {
cartProducts: (state, getters, rootState) => {
return state.items.map(({
id, quantity }) => {
const product = rootState.products.all.find(product => product.id === id)
return {
title: product.title,
price: product.price,
quantity
}
})
},
cartTotalPrice: (state, getters) => {
return getters.cartProducts.reduce((total, product) => {
return total + product.price * product.quantity
}, 0)
}
}
// actions
const actions = {
checkout ({
commit, state }, products) {
const savedCartItems = [...state.items]
commit('setCheckoutStatus', null)
// empty cart
commit('setCartItems', {
items: [] })
shop.buyProducts(
products,
() => commit('setCheckoutStatus', 'successful'),
() => {
commit('setCheckoutStatus', 'failed')
// rollback to the cart saved before sending the request
commit('setCartItems', {
items: savedCartItems })
}
)
},
addProductToCart ({
state, commit }, product) {
commit('setCheckoutStatus', null)
if (product.inventory > 0) {
const cartItem = state.items.find(item => item.id === product.id)
if (!cartItem) {
commit('pushProductToCart', {
id: product.id })
} else {
commit('incrementItemQuantity', cartItem)
}
// remove 1 item from stock
commit('products/decrementProductInventory', {
id: product.id }, {
root: true })
}
}
}
// mutations
const mutations = {
pushProductToCart (state, {
id }) {
state.items.push({
id,
quantity: 1
})
},
incrementItemQuantity (state, {
id }) {
const cartItem = state.items.find(item => item.id === id)
cartItem.quantity++
},
setCartItems (state, {
items }) {
state.items = items
},
setCheckoutStatus (state, status) {
state.checkoutStatus = status
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}