一.购物车数量前端数据渲染
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;
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;
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 {
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;
18px;
height: 18px;
border: 1px solid crimson;
color: crimson;
border-radius: 9px;
text-align: center;
line-height: 18px;
}
input {
28px;
border: none 0px;
outline: none;
text-align: center;
}
b {
font-weight: normal;
margin-left: 10px;
font-size: 13px;
}
}
}
}
}
}
.total-pad {
height: 58px;
100%;
background-color: #383838;
position: fixed;
left: 0;
bottom: 40px;
i {
display: inline-block;
border: 1px solid #a9a9a9;
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;
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;
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;
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 {
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;
18px;
height: 18px;
border: 1px solid crimson;
color: crimson;
border-radius: 9px;
text-align: center;
line-height: 18px;
}
input {
28px;
border: none 0px;
outline: none;
text-align: center;
}
b {
font-weight: normal;
margin-left: 10px;
font-size: 13px;
}
}
}
}
}
}
.total-pad {
height: 58px;
100%;
background-color: #383838;
position: fixed;
left: 0;
bottom: 40px;
i {
display: inline-block;
border: 1px solid #a9a9a9;
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;
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;
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;
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 {
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;
18px;
height: 18px;
border: 1px solid crimson;
color: crimson;
border-radius: 9px;
text-align: center;
line-height: 18px;
}
input {
28px;
border: none 0px;
outline: none;
text-align: center;
}
b {
font-weight: normal;
margin-left: 10px;
font-size: 13px;
}
}
}
}
}
}
.total-pad {
height: 58px;
100%;
background-color: #383838;
position: fixed;
left: 0;
bottom: 40px;
i {
display: inline-block;
border: 1px solid #a9a9a9;
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;
120px;
border: 0 none;
background-color: #ddd;
color: #aaa;
font-size: 15px;
font-weight: bold;
}
}
</style>