vue3微信公众号商城项目实战系列(9)购物车页面
本篇显示购物车中的商品,购物车表结构如下,我们通过接口服务抓取登录用户的购物车信息。
表名 |
字段 |
功能 |
shoppingcart |
cart_id (int) 购物车编号 user_id (int) 用户编号 goods_id (int) 商品编号 goods_name (varchar) 商品名称 photo (varchar) 商品图片 price (decimal) 价格 qty (int) 数量 |
购物车表 |
页面效果如下:
先在 app.js 中增加查询购物车商品、创建订单的接口方法,如下:
1 export function cartQuery(data) { 2 return request({ 3 url: '/cart/query', 4 method: 'post', 5 data: data 6 }) 7 } 8 9 export function orderBuild(data) { 10 return request({ 11 url: '/order/build', 12 method: 'post', 13 data: data 14 }) 15 }
下面来看 cart.js 的代码
布局代码块:
1 <template> 2 <div class="cart"> 3 <div class="cart-list"> 4 <div class="cart-item" v-for="(item,index) in cartList"> 5 <div><img class="cart-img" :src="item.photo" /></div> 6 <div class="cart-info"> 7 <div><span class="cart-name">{{ item.goodsName }}</span></div> 8 <span class="cart-price">¥{{ item.price }}元</span> 9 <div class="cart-qty"> 10 <input class="txt_qty" type="number" v-model="item.qty" @blur="onModifyCart(item.goodsId, index)" /> 11 <span class="cart-price">{{ item.price * item.qty }} 元</span> 12 </div> 13 </div> 14 </div> 15 </div> 16 <div class="cart-total"> 17 <span class="cart-price">总价 : {{ totalAmt }}元</span> 18 <input class="btn_order" type="button" value="下单" @click="onOrder" /> 19 </div> 20 21 <TabBar name="cart" /> 22 </div> 23 </template>
使用 v-for 遍历数组 cartList ,onModifyCart 是输入框的失去焦点事件,用户可以修改商品数量。
脚本代码块:
1 <script setup> 2 import { onMounted, reactive, toRefs, computed } from 'vue'; 3 import {cartQuery, cartAdd} from '@/http/api'; 4 import TabBar from '@/components/TabBar.vue'; 5 import { useCartStore } from '@/stores/cart.js' 6 const cartStore = useCartStore(); 7 8 const data = reactive({cartList:[] }) 9 let {cartList} = toRefs(data); 10 11 const totalAmt = computed(() => { 12 let ttl=0; 13 data.cartList.forEach(function(item, index) {ttl+=item.price * item.qty;}); 14 return ttl; 15 }) 16 17 onMounted(() => { 18 let formData={}; 19 cartQuery(formData).then(res=>{ 20 data.cartList=res; 21 }); 22 }) 23 24 function onModifyCart(goodsId, index){ 25 let newQty=data.cartList[index].qty 26 let formData = {goodsId:goodsId,qty:newQty}; 27 //console.log(JSON.stringify(formData)); 28 cartAdd(formData).then(res=>{ 29 cartStore.reset(res.qty); 30 }) 31 }
function onOrder(){
let cartinfo = '';
data.cartList.forEach((item, index)=>{
cartinfo+=','+item.goodsId+':'+item.qty;
});
cartinfo=cartinfo.substring(1);
let formData={cartinfo:cartinfo};
orderBuild(formData).then(res=>{
router.push({name:'order',query:{oid:res.orderId}});
})
}
</script>
和 Home.vue 大部分是相同的,不同的见红色部分。
1 . 使用了 vue3 的 computed() 函数,它能将 totalAmt 这个变量变成一个计算属性,其作用就是汇总购物车中商品总额
,然后在总价那里显示出来。
2. cartAdd() 这个后端接口会返回一个 qty ,它表示当前用户购物车中商品的总数量,每次更新购物车商品数量
,后端接口都需要重新计算一下总数量,前端可以用这个值更新 cart.count ,确保商品数量同步。
3. let newQty=data.cartList[index].qty 这里可以取到用户输入的值,因为 cartList 是一个响应式对象
,用户输入的值 vue3 框架会自动帮我们设置到相应索引的qty属性中去。
4. reset() 方法 是 cart状态 中新增的方法,用于重置数量,修改后的代码如下(见红色部分):
1 import { ref } from 'vue'; 2 import {defineStore} from 'pinia'; 3 4 export const useCartStore = defineStore('cart', () => { 5 const count = ref(0); 6 function increment(qty) { 7 count.value += qty; 8 } 9 function reduction(qty){ 10 if(count.value>1){ 11 count.value -= qty; 12 } 13 } 14 function reset(qty){ 15 count.value=qty; 16 } 17 return { count, increment, reduction, reset } 18 }, 19 {persist:true} 20 )
其他两个方法也做了改进,可以根据参数来做增减。
5. onOrder() 方法遍历购物车中的商品信息,调用 orderBuild( ) 来生成订单,该方法的返回值是新生成订单的编号
,调用 router.push({name:'order',query:{oid:res.orderId}}); 方法时会自动生成查询字符串,形如 " ?oid=237832 "
,实际项目中每个商品前有 checkbox 可以让用户勾选,这里做了简化处理。
样式代码块:
1 <style> 2 .cart-list{ 3 display: flex; 4 flex-direction: column; 5 } 6 .cart-item{ 7 display: flex; 8 flex-direction: row; 9 border:solid 1px #E0E0E0; 10 margin-bottom: 6px; 11 padding: 4px 0; 12 } 13 .cart-img{ 14 width: 100px; 15 height: 100px; 16 vertical-align: middle; 17 border: solid 1px #F0F0F0; 18 border-radius: 4px; 19 } 20 .cart-info{ 21 width: 100%; 22 padding-left: 8px; 23 padding-right: 8px; 24 } 25 .cart-name{ 26 font-weight: bold; 27 } 28 .cart-price{ 29 font-size: 16px; 30 font-weight: bold; 31 color:orangered; 32 } 33 .cart-qty{ 34 width: 100%; 35 display: flex; 36 flex-direction: row; 37 justify-content: space-between; 38 } 39 .txt_qty{ 40 width: 60px; 41 } 42 43 .cart-total{ 44 width: 368px; 45 height: 30px; 46 line-height: 30px; 47 position: fixed; 48 left: 3px; 49 bottom: 56px; 50 background-color: #e0fffe; 51 52 display: flex; 53 flex-direction: row; 54 justify-content: space-between; 55 } 56 .btn_order{ 57 width: 70px; 58 height: 30px; 59 } 60 </style>
这里根据页面布局要求来设置就可以了。