feature: 购物车完整demo
This commit is contained in:
parent
ca37a1831f
commit
6dece8bccc
0
public/product.json
Normal file
0
public/product.json
Normal file
22
src/App.vue
22
src/App.vue
@ -1,26 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<HelloWorld/>
|
<product-page></product-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from "vue";
|
||||||
import HelloWorld from './components/HelloWorld.vue';
|
import ProductPage from './components/ProductPage.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
HelloWorld
|
ProductPage
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#app {
|
|
||||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
text-align: center;
|
|
||||||
color: #2c3e50;
|
|
||||||
margin-top: 60px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
35
src/api/shop.ts
Normal file
35
src/api/shop.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
export interface IProduct {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
price: number
|
||||||
|
inventory: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const _products: IProduct[] = [
|
||||||
|
{
|
||||||
|
"id": "0",
|
||||||
|
"name": "IPad Pro",
|
||||||
|
"price": 5999,
|
||||||
|
"inventory": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"name": "IPhone 13 Pro",
|
||||||
|
"price": 7999,
|
||||||
|
"inventory": 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const getProducts = async () => {
|
||||||
|
await wait(1000)
|
||||||
|
return _products
|
||||||
|
}
|
||||||
|
|
||||||
|
export const buyProducts = async () => {
|
||||||
|
await wait(1000)
|
||||||
|
return Math.random() > 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
async function wait( delay: number ) {
|
||||||
|
return new Promise(( resolve ) => setTimeout(resolve, delay))
|
||||||
|
}
|
@ -9,7 +9,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { userMainStore } from "@/store";
|
import { userMainStore } from "@/store";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
const mainStore = userMainStore()
|
const mainStore = userMainStore()
|
||||||
console.log(mainStore.count)
|
console.log(mainStore.count)
|
||||||
|
35
src/components/ProductPage.vue
Normal file
35
src/components/ProductPage.vue
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<template>
|
||||||
|
<h2>Pinia —— 购物车示例</h2>
|
||||||
|
<hr>
|
||||||
|
<h3>商品列表</h3>
|
||||||
|
<ul>
|
||||||
|
<li v-for="item in productStore.all" :key="item.id">
|
||||||
|
<p>{{ item.name }} -- {{ item.price }} -- 库存:{{ item.inventory }}</p>
|
||||||
|
<button :disabled="item.inventory===0" @click="cartStore.addProductToCart(item)">添加到购物车</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<hr>
|
||||||
|
<h3>你的购物车</h3>
|
||||||
|
<ul>
|
||||||
|
<li v-for="item in cartStore.cartProducts" :key="item.id">
|
||||||
|
<p>{{ item.name }} -- 价格 {{ item.price }} x {{ item.quantity }}</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>商品总价:{{ cartStore.totalPrice }}</p>
|
||||||
|
<button @click="cartStore.checkout()">结算</button>
|
||||||
|
<p>{{ cartStore.checkStatus }}</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useProductStore } from "@/store/product";
|
||||||
|
import { useCartStore } from "@/store/cart";
|
||||||
|
|
||||||
|
const productStore = useProductStore()
|
||||||
|
const cartStore = useCartStore()
|
||||||
|
|
||||||
|
productStore.loadAllProducts()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
57
src/store/cart.ts
Normal file
57
src/store/cart.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { buyProducts, IProduct } from "@/api/shop";
|
||||||
|
import { useProductStore } from "@/store/product";
|
||||||
|
|
||||||
|
type CartProduct = {
|
||||||
|
quantity: number
|
||||||
|
} & IProduct
|
||||||
|
|
||||||
|
enum checkoutStatus {
|
||||||
|
PENDING = "未结算",
|
||||||
|
SUCCESS = "结算成功",
|
||||||
|
FALSE = "结算失败"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useCartStore = defineStore('cart', {
|
||||||
|
state: () => ( {
|
||||||
|
cartProducts: [] as CartProduct[],
|
||||||
|
checkStatus: checkoutStatus.PENDING
|
||||||
|
} ),
|
||||||
|
getters: {
|
||||||
|
totalPrice( state ) {
|
||||||
|
return state.cartProducts.reduce(( pre, cur ) => {
|
||||||
|
return pre + cur.price * cur.quantity
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
addProductToCart( product: IProduct ) {
|
||||||
|
if ( product.inventory < 1 ) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const cartItem: CartProduct | undefined = this.cartProducts.find(item => item.id === product.id)
|
||||||
|
if ( cartItem ) {
|
||||||
|
cartItem.quantity++
|
||||||
|
} else {
|
||||||
|
this.cartProducts.push({
|
||||||
|
id: product.id,
|
||||||
|
name: product.name,
|
||||||
|
inventory: product.inventory,
|
||||||
|
price: product.price,
|
||||||
|
quantity: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const productStore = useProductStore()
|
||||||
|
productStore.decrementProductInventory(product)
|
||||||
|
},
|
||||||
|
async checkout() {
|
||||||
|
const result = await buyProducts()
|
||||||
|
if ( result ) {
|
||||||
|
this.checkStatus = checkoutStatus.SUCCESS
|
||||||
|
this.cartProducts = []
|
||||||
|
} else {
|
||||||
|
this.checkStatus = checkoutStatus.FALSE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
20
src/store/product.ts
Normal file
20
src/store/product.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { getProducts, IProduct } from "@/api/shop";
|
||||||
|
|
||||||
|
export const useProductStore = defineStore('product', {
|
||||||
|
state: () => ( {
|
||||||
|
all: [] as IProduct[]
|
||||||
|
} ),
|
||||||
|
getters: {},
|
||||||
|
actions: {
|
||||||
|
async loadAllProducts() {
|
||||||
|
this.all = await getProducts()
|
||||||
|
},
|
||||||
|
decrementProductInventory( product: IProduct ) {
|
||||||
|
const productItem = this.all.find(item => item.id === product.id)
|
||||||
|
if ( productItem ) {
|
||||||
|
productItem.inventory--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user