一、新建一个模块
在代码层根目录下新建一个文件夹store
在入口main.js引入store模块,import store from './store'
二、修改页面
1、email的值,通过mapState的方法获取到
2、引入组件ProductList和ShoppingCart
<template>
<div id="app">
<h1>购物车示例</h1>
<p>账号: {{email}}</p>
<hr>
<h2>产品</h2>
<ProductList/>
<hr>
<ShoppingCart/>
</div>
</template>
<script>
import { mapState } from 'vuex'
import ProductList from './components/ProductList.vue'
import ShoppingCart from './components/ShoppingCart.vue'
export default {
computed: mapState({
email: state => state.userInfo.email
}),
components: { ProductList, ShoppingCart },
}
</script>
三、新建组件
1、新建组件ProductList
在目录components下新建ProductList.vue
<template>
<ul>
<li
v-for="product in products"
:key="product.id">
{{ product.title }} - {{ product.price }}
<br>
<button
:disabled="!product.inventory"
@click="addProductToCart(product)">
加入购物车
</button>
</li>
</ul>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
computed: mapState({
products: state => state.products.all,
}),
// mapState方法等同于
// computed: {
// products(){
// return this.$store.state.products.all
// }
// },
//第一个参数cart 是命名空间
methods: mapActions('cart', [
'addProductToCart'
]),
// mapActions方法等同于
// methods: {
// addProductToCart(product){
// this.$store.dispatch('cart/addProductToCart', product)
// }
// },
created () {
this.$store.dispatch('products/getAllProducts')
}
}
</script>
2、新建组件ShoppingCart
在目录components下新建ShoppingCart.vue
<template>
<div class="cart">
<h2>清单</h2>
<p v-show="!products.length"><i>请添加产品到购物车</i></p>
<ul>
<li
v-for="product in products"
:key="product.id">
{{ product.title }} - {{ product.price }} x {{ product.quantity }}
</li>
</ul>
<p>合计: {{ total }}</p>
<p><button :disabled="!products.length" @click="checkout(products)">提交</button></p>
<p v-show="checkoutStatus">提交 {{ checkoutStatus }}.</p>
</div>
</template>
<script>
import { mapGetters, mapState } from 'vuex'
export default {
computed: {
...mapState({
checkoutStatus: state => state.cart.checkoutStatus
}),
...mapGetters('cart', {
products: 'cartProducts',
total: 'cartTotalPrice'
}),
// ...mapGetters({
// products: 'cart/cartProducts',
// total: 'cart/cartTotalPrice'
// })
},
// computed: {
// checkoutStatus(){
// return this.$store.state.cart.checkoutStatus
// },
// products() {
// return this.$store.getters['cart/cartProducts']
// },
// total() {
// return this.$store.getters['cart/cartTotalPrice']
// }
// },
methods: {
checkout (products) {
this.$store.dispatch('cart/checkout', products)
}
},
}
</script>
四、store模块的入口文件
在store文件夹下新建index.js,引入cart和products组件,并注册到modules上
import Vue from 'vue'
import Vuex from 'vuex'
import cart from './modules/cart'
import products from './modules/products'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
userInfo: {
email: "xxxxxx@qq.com"
}
},
modules: {
cart,
products
},
})
五、products.js
import shop from '../../api/shop'
import {PRODUCTS} from '../mutation-types'
// initial state
const state = {
all: []
}
// getters
const getters = {}
// actions
const actions = {
getAllProducts ({ commit }) {
shop.getProducts(products => {
commit(PRODUCTS.SET_PRODUCTS, products)
})
}
}
// mutations
const mutations = {
[PRODUCTS.SET_PRODUCTS] (state, products) {
state.all = products
},
[PRODUCTS.DECREMENT_PRODUCT_INVENTORY] (state, { id }) {
const product = state.all.find(product => product.id === id)
product.inventory--
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
六、模块cart.js
import shop from '../../api/shop'
import { CART, PRODUCTS } from '../mutation-types'
// 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(CART.SET_CHECKOUT_STATUS, null)
// empty cart
commit(CART.SET_CART_ITEMS, { items: [] })
shop.buyProducts(
products,
() => commit(CART.SET_CHECKOUT_STATUS, 'successful'),
() => {
commit(CART.SET_CHECKOUT_STATUS, 'failed')
// rollback to the cart saved before sending the request
commit(CART.SET_CART_ITEMS, { items: savedCartItems })
}
)
},
addProductToCart ({ state, commit }, product) {
commit(CART.SET_CHECKOUT_STATUS, null)
if (product.inventory > 0) {
const cartItem = state.items.find(item => item.id === product.id)
if (!cartItem) {
commit(CART.PUSH_PRODUCT_TO_CART, { id: product.id })
} else {
commit(CART.INCREMENT_ITEM_QUANTITY, cartItem)
}
// remove 1 item from stock
commit(`products/${PRODUCTS.DECREMENT_PRODUCT_INVENTORY}`, { id: product.id }, { root: true })
}
}
}
// mutations
const mutations = {
[CART.PUSH_PRODUCT_TO_CART] (state, { id }) {
state.items.push({
id,
quantity: 1
})
},
[CART.INCREMENT_ITEM_QUANTITY] (state, { id }) {
const cartItem = state.items.find(item => item.id === id)
cartItem.quantity++
},
[CART.SET_CART_ITEMS] (state, { items }) {
state.items = items
},
[CART.SET_CHECKOUT_STATUS] (state, status) {
state.checkoutStatus = status
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
七、api
/**
* Mocking client-server processing
*/
const _products = [
{"id": 1, "title": "华为 Mate 20", "price": 3999, "inventory": 2},
{"id": 2, "title": "小米 9", "price": 2999, "inventory": 0},
{"id": 3, "title": "OPPO R17", "price": 2999, "inventory": 5}
]
export default {
getProducts (cb) {
setTimeout(() => cb(_products), 100)
},
buyProducts (products, cb, errorCb) {
setTimeout(() => {
// simulate random checkout failure.
Math.random() > 0.5
? cb()
: errorCb()
}, 100)
}
}
网友评论