.NET經銷商實戰(十五)——購物車介面改造,全選功能實現與完善
阿新 • • 發佈:2022-06-05
一.購物車數量前端資料渲染
1.ShoppingCart.vue程式碼如下:
點選檢視程式碼
<template> <div> <div class="cart-list"> <ul> <li v-for="type in types" :key="type.typeNo"> <p> <i></i> <span>{{ transTypeWhenNull(type.typeName) }}</span> </p> <template v-for="cart in carts" :key="cart.cartGuid"> <div v-if="cart.productDto?.typeNo == type.typeNo"> <i></i> <img src="" alt="" /> <p class="p-name">{{ cart.productDto?.productName }}</p> <p class="p-price">¥{{}}</p> <p class="p-num"> <span class="sub-num" @click="onSubNum(cart)">-</span> <input v-model="cart.productNum" @change="onChangeNum(cart)" /> <span class="add0num" @click="onAddNum(cart)">+</span> <b>塊</b> </p> </div> </template> </li> </ul> </div> <div class="total-pad"> <i></i> <span>全選</span> <span> 合計:¥ <b>{{ totalPrice | price }}</b> </span> <button>確定下單</button> </div> </div> </template> <script> import { reactive, toRefs, onMounted } from 'vue' import { getCarts } from '@/httpRequests/ShoppingCartRequest' export default { // mounted() { // this.$store.comm // this.$store.dispatch('setFootMenuIndexAsync', 2) // }, setup() { //資料發生改變時,這個方式不能及時獲取變化後的資料 //const productNumRef = ref() const shoppingCartInfo = reactive({ carts: [], types: [], // buyNum: 1, totalPrice: 6888, onAddNum(cart) { cart.productNum++ }, onSubNum(cart) { if (cart.productNum > 1) { cart.productNum-- } }, onChangeNum(cart) { var currNum = event.target.value if (!isNaN(currNum) && currNum > 0) { cart.productNum = currNum } else { event.target.value = cart.productNum } }, onGetShoppingCarts: async () => { var customerNo = localStorage['customerNo'] var res = await getCarts(customerNo) shoppingCartInfo.carts = res.carts shoppingCartInfo.types = res.types console.log(res) }, transTypeWhenNull: (typeName) => typeName ?? '未分類產品', }) onMounted(() => { shoppingCartInfo.onGetShoppingCarts() }) return { ...toRefs(shoppingCartInfo) } }, } </script> <style lang="scss" scoped> .cart-list { text-align: left; ul { margin-bottom: 108px; li { background-color: #fff; margin-bottom: 12px; > p { padding-left: 46px; position: relative; height: 46px; border-bottom: 1px solid #ddd; i { border: 1px solid #a9a9a9; width: 18px; height: 18px; line-height: 18px; border-radius: 18px; position: absolute; left: 13px; top: 13px; text-align: center; font-size: 12px; color: #fff; font-style: normal; } i.cart-select { background-color: crimson; border: 1px solid crimson; } span { display: inline-block; border-left: 3px solid crimson; height: 28px; margin: 9px 0; padding-left: 8px; line-height: 30px; } } div { padding-left: 46px; position: relative; height: 98px; padding: 8px 14px 8px 148px; i { border: 1px solid #a9a9a9; width: 18px; height: 18px; line-height: 18px; border-radius: 18px; position: absolute; left: 13px; top: 28px; text-align: center; font-size: 12px; color: #fff; font-style: normal; } i.cart-select { background-color: crimson; border: 1px solid crimson; } img { width: 68px; height: 68px; background-color: #ccc; position: absolute; left: 58px; top: 20px; } p.p-name { font-size: 13px; margin-top: 10px; height: 30px; } p.p-price { font-size: 13px; height: 20px; color: crimson; } p.p-num { text-align: right; padding-right: 20px; span { display: inline-block; width: 18px; height: 18px; border: 1px solid crimson; color: crimson; border-radius: 9px; text-align: center; line-height: 18px; } input { width: 28px; border: none 0px; outline: none; text-align: center; } b { font-weight: normal; margin-left: 10px; font-size: 13px; } } } } } } .total-pad { height: 58px; width: 100%; background-color: #383838; position: fixed; left: 0; bottom: 40px; i { display: inline-block; border: 1px solid #a9a9a9; width: 18px; height: 18px; line-height: 18px; border-radius: 18px; background-color: #fff; margin-left: 13px; margin-top: 20px; vertical-align: bottom; height: 18px; text-align: center; font-size: 12px; color: #fff; font-style: italic; } i.cart-select { background-color: crimson; border: 1px solid crimson; } span { color: #fff; margin-left: 6px; font-size: 13px; b { font-size: 15px; } } button { float: right; height: 58px; width: 120px; border: 0 none; background-color: #ddd; color: #aaa; font-size: 15px; font-weight: bold; } } </style>
2.後端ShoppingCartController控制器中修改GetShoppingCartDtos方法
增加一個返回值TypeSeleted,預設賦值為false,這裡我只是為了偷懶,所有用了dynamic,公司開發中最好不要用dynamic,否則會被人噴死
3.shoppingCart前端全選功能實現
點選檢視程式碼
<template> <div> <div class="cart-list"> <ul> <li v-for="type in types" :key="type.typeNo"> <p> <i :class="{ 'cart-select': type.typeSelected }">√</i> <span>{{ transTypeWhenNull(type.typeName) }}</span> </p> <template v-for="cart in carts" :key="cart.cartGuid"> <div v-if="cart.productDto?.typeNo == type.typeNo"> <i :class="{ 'cart-select': cart.cartSelected }" @click="onSelectCart(cart)" >√</i > <img src="" alt="" /> <p class="p-name">{{ cart.productDto?.productName }}</p> <p class="p-price">¥{{}}</p> <p class="p-num"> <span class="sub-num" @click="onSubNum(cart)">-</span> <input v-model="cart.productNum" @change="onChangeNum(cart)" /> <span class="add0num" @click="onAddNum(cart)">+</span> <b>塊</b> </p> </div> </template> </li> </ul> </div> <div class="total-pad"> <i></i> <span>全選</span> <span> 合計:¥ <b>{{ totalPrice | price }}</b> </span> <button>確定下單</button> </div> </div> </template> <script> import { reactive, toRefs, onMounted } from 'vue' import { getCarts } from '@/httpRequests/ShoppingCartRequest' export default { // mounted() { // this.$store.comm // this.$store.dispatch('setFootMenuIndexAsync', 2) // }, setup() { //資料發生改變時,這個方式不能及時獲取變化後的資料 //const productNumRef = ref() const shoppingCartInfo = reactive({ carts: [], types: [], // buyNum: 1, totalPrice: 6888, onAddNum(cart) { cart.productNum++ }, onSubNum(cart) { if (cart.productNum > 1) { cart.productNum-- } }, onChangeNum(cart) { var currNum = event.target.value if (!isNaN(currNum) && currNum > 0) { cart.productNum = currNum } else { event.target.value = cart.productNum } }, onGetShoppingCarts: async () => { var customerNo = localStorage['customerNo'] var res = await getCarts(customerNo) shoppingCartInfo.carts = res.carts shoppingCartInfo.types = res.types // console.log(res) }, onSelectCart: (cart) => { cart.cartSelected = !cart.cartSelected //找到型別中對應設定物品的型別 var type = shoppingCartInfo.types.filter( (m) => m.typeNo == cart.productDto?.typeNo )[0] var cartsOfType = shoppingCartInfo.carts.filter( (s) => s.productDto?.typeNo == type?.typeNo ) if (cartsOfType.every((m) => m.cartSelected)) { type.typeSelected = true } else { type.typeSelected = false } }, transTypeWhenNull: (typeName) => typeName ?? '未分類產品', }) onMounted(() => { shoppingCartInfo.onGetShoppingCarts() }) return { ...toRefs(shoppingCartInfo) } }, } </script> <style lang="scss" scoped> .cart-list { text-align: left; ul { margin-bottom: 108px; li { background-color: #fff; margin-bottom: 12px; > p { padding-left: 46px; position: relative; height: 46px; border-bottom: 1px solid #ddd; i { border: 1px solid #a9a9a9; width: 18px; height: 18px; line-height: 18px; border-radius: 18px; position: absolute; left: 13px; top: 13px; text-align: center; font-size: 12px; color: #fff; font-style: normal; } i.cart-select { background-color: crimson; border: 1px solid crimson; } span { display: inline-block; border-left: 3px solid crimson; height: 28px; margin: 9px 0; padding-left: 8px; line-height: 30px; } } div { padding-left: 46px; position: relative; height: 98px; padding: 8px 14px 8px 148px; i { border: 1px solid #a9a9a9; width: 18px; height: 18px; line-height: 18px; border-radius: 18px; position: absolute; left: 13px; top: 28px; text-align: center; font-size: 12px; color: #fff; font-style: normal; } i.cart-select { background-color: crimson; border: 1px solid crimson; } img { width: 68px; height: 68px; background-color: #ccc; position: absolute; left: 58px; top: 20px; } p.p-name { font-size: 13px; margin-top: 10px; height: 30px; } p.p-price { font-size: 13px; height: 20px; color: crimson; } p.p-num { text-align: right; padding-right: 20px; span { display: inline-block; width: 18px; height: 18px; border: 1px solid crimson; color: crimson; border-radius: 9px; text-align: center; line-height: 18px; } input { width: 28px; border: none 0px; outline: none; text-align: center; } b { font-weight: normal; margin-left: 10px; font-size: 13px; } } } } } } .total-pad { height: 58px; width: 100%; background-color: #383838; position: fixed; left: 0; bottom: 40px; i { display: inline-block; border: 1px solid #a9a9a9; width: 18px; height: 18px; line-height: 18px; border-radius: 18px; background-color: #fff; margin-left: 13px; margin-top: 20px; vertical-align: bottom; height: 18px; text-align: center; font-size: 12px; color: #fff; font-style: italic; } i.cart-select { background-color: crimson; border: 1px solid crimson; } span { color: #fff; margin-left: 6px; font-size: 13px; b { font-size: 15px; } } button { float: right; height: 58px; width: 120px; border: 0 none; background-color: #ddd; color: #aaa; font-size: 15px; font-weight: bold; } } </style>
4.全選功能完善
購物車介面
點選檢視程式碼
<template> <div> <div class="cart-list"> <ul> <li v-for="type in types" :key="type.typeNo"> <p> <i :class="{ 'cart-select': type.typeSelected }" @click="onSelectType(type)" >√</i > <span>{{ transTypeWhenNull(type.typeName) }}</span> </p> <template v-for="cart in carts" :key="cart.cartGuid"> <div v-if="cart.productDto?.typeNo == type.typeNo"> <i :class="{ 'cart-select': cart.cartSelected }" @click="onSelectCart(cart)" >√</i > <img src="" alt="" /> <p class="p-name">{{ cart.productDto?.productName }}</p> <p class="p-price">¥{{}}</p> <p class="p-num"> <span class="sub-num" @click="onSubNum(cart)">-</span> <input v-model="cart.productNum" @change="onChangeNum(cart)" /> <span class="add0num" @click="onAddNum(cart)">+</span> <b>塊</b> </p> </div> </template> </li> </ul> </div> <div class="total-pad"> <i :class="{ 'cart-select': isAllSelected }">√</i> <span>全選</span> <span> 合計:¥ <b>{{ totalPrice | price }}</b> </span> <button>確定下單</button> </div> </div> </template> <script> import { reactive, toRefs, onMounted } from 'vue' import { getCarts } from '@/httpRequests/ShoppingCartRequest' export default { // mounted() { // this.$store.comm // this.$store.dispatch('setFootMenuIndexAsync', 2) // }, setup() { //資料發生改變時,這個方式不能及時獲取變化後的資料 //const productNumRef = ref() const shoppingCartInfo = reactive({ carts: [], types: [], isAllSelected: true, // buyNum: 1, totalPrice: 6888, onAddNum(cart) { cart.productNum++ }, onSubNum(cart) { if (cart.productNum > 1) { cart.productNum-- } }, onChangeNum(cart) { var currNum = event.target.value if (!isNaN(currNum) && currNum > 0) { cart.productNum = currNum } else { event.target.value = cart.productNum } }, /** * 獲取購物車資訊 */ onGetShoppingCarts: async () => { var customerNo = localStorage['customerNo'] var res = await getCarts(customerNo) shoppingCartInfo.carts = res.carts shoppingCartInfo.types = res.types // console.log(res) }, /** * 點選選擇購物車時觸發 */ onSelectCart: (cart) => { cart.cartSelected = !cart.cartSelected //找到型別中對應設定物品的型別 // var type = shoppingCartInfo.types.filter( // (m) => m.typeNo == cart.productDto?.typeNo // )[0] // var cartsOfType = shoppingCartInfo.carts.filter( // (s) => s.productDto?.typeNo == type?.typeNo // ) shoppingCartInfo.checkTypeSelected() }, /** * 選擇型別時觸發 */ onSelectType: (type) => { type.typeSelected = !type.typeSelected shoppingCartInfo.carts .filter((s) => s.productDto?.typeNo == type?.typeNo) .forEach((s) => { s.cartSelected = type.typeSelected }) shoppingCartInfo.checkAllSelected() }, checkTypeSelected: () => { shoppingCartInfo.types.forEach((type) => { var cartsOfType = shoppingCartInfo.carts.filter( (s) => s.productDto?.typeNo == type?.typeNo ) //檢視當前型別下的物品是否都被選擇,是則將屬於型別選中 //否則不選中 if (cartsOfType.every((m) => m.cartSelected)) { type.typeSelected = true } else { type.typeSelected = false } }) shoppingCartInfo.checkAllSelected() }, //全選 合計 checkAllSelected: () => { if (shoppingCartInfo.carts.every((m) => m.cartSelected)) { shoppingCartInfo.isAllSelected = true } else { shoppingCartInfo.isAllSelected = false } }, transTypeWhenNull: (typeName) => typeName ?? '未分類產品', }) onMounted(() => { shoppingCartInfo.onGetShoppingCarts() shoppingCartInfo.checkTypeSelected() }) return { ...toRefs(shoppingCartInfo) } }, } </script> <style lang="scss" scoped> .cart-list { text-align: left; ul { margin-bottom: 108px; li { background-color: #fff; margin-bottom: 12px; > p { padding-left: 46px; position: relative; height: 46px; border-bottom: 1px solid #ddd; i { border: 1px solid #a9a9a9; width: 18px; height: 18px; line-height: 18px; border-radius: 18px; position: absolute; left: 13px; top: 13px; text-align: center; font-size: 12px; color: #fff; font-style: normal; } i.cart-select { background-color: crimson; border: 1px solid crimson; } span { display: inline-block; border-left: 3px solid crimson; height: 28px; margin: 9px 0; padding-left: 8px; line-height: 30px; } } div { padding-left: 46px; position: relative; height: 98px; padding: 8px 14px 8px 148px; i { border: 1px solid #a9a9a9; width: 18px; height: 18px; line-height: 18px; border-radius: 18px; position: absolute; left: 13px; top: 28px; text-align: center; font-size: 12px; color: #fff; font-style: normal; } i.cart-select { background-color: crimson; border: 1px solid crimson; } img { width: 68px; height: 68px; background-color: #ccc; position: absolute; left: 58px; top: 20px; } p.p-name { font-size: 13px; margin-top: 10px; height: 30px; } p.p-price { font-size: 13px; height: 20px; color: crimson; } p.p-num { text-align: right; padding-right: 20px; span { display: inline-block; width: 18px; height: 18px; border: 1px solid crimson; color: crimson; border-radius: 9px; text-align: center; line-height: 18px; } input { width: 28px; border: none 0px; outline: none; text-align: center; } b { font-weight: normal; margin-left: 10px; font-size: 13px; } } } } } } .total-pad { height: 58px; width: 100%; background-color: #383838; position: fixed; left: 0; bottom: 40px; i { display: inline-block; border: 1px solid #a9a9a9; width: 18px; height: 18px; line-height: 18px; border-radius: 18px; background-color: #fff; margin-left: 13px; margin-top: 20px; vertical-align: bottom; height: 18px; text-align: center; font-size: 12px; color: #fff; font-style: normal; } i.cart-select { background-color: crimson; border: 1px solid crimson; } span { color: #fff; margin-left: 6px; font-size: 13px; b { font-size: 15px; } } button { float: right; height: 58px; width: 120px; border: 0 none; background-color: #ddd; color: #aaa; font-size: 15px; font-weight: bold; } } </style>