用Vue实现购物车组件
前言本实例主要介绍利用Vue实现购物车组件,顶部可以切换标签“全部”、“好评”和“买过”的数据,标签“全部”下还可以切换不同分类显示商品;也可对商品进行加减,并进行跨标签和跨分类的最终价合计;最终效果:实现过程一. 子组件代码如下(shoppingCart.vue),原理分析:1. 切换标签函数toggleType,点击时,赋值this.currentIndex = index,同时利用计算属性更
前言
本实例主要介绍利用Vue实现购物车组件,顶部可以切换标签“全部”、“好评”和“买过”的数据,标签“全部”下还可以切换不同分类显示商品;也可对商品进行加减,并进行跨标签和跨分类的最终价合计;
最终效果:
实现过程
一. 子组件代码如下(shoppingCart.vue),原理分析:
1. 切换标签函数toggleType,点击时,赋值this.currentIndex = index,同时利用计算属性更新menu的值,从而实现切换标签数据功能;而this.menuTypeIndex = 0为了解决从多分类到少分类切换报错的问题;
2. 切换分类函数toggleGoods,点击时,赋值this.menuTypeIndex = index,同时利用计算属性更新goods的值,从而实现切换分类数据功能;
3. 添加函数clickAdd,每次点击时,数量加1,同时利用JQ实现一个商品图片从上往下掉落到配送员箱子的过程;然后箱子的数字加1,并增加原价、优惠价和配送费用等;
4. 减少函数clickMinus,每次点击时,数量减1,同时减少原价、优惠价和配送费用等。
<template>
<div class="sc-box">
<div class="sc-type">
<ul>
<li :class="{active:currentIndex === index}" v-for="(item, index) in goodsList" :key="index" data-index="index" @click="toggleType(index)">{{item.type}}</li>
</ul>
</div>
<div class="sc-content">
<div class="sc-leftMenu" v-if="menu.length > 1">
<ul>
<li :class="{active:menuTypeIndex === index}" v-for="(item, index) in menu" :key="index" data-index="index" @click="toggleGoods(index)">{{item.menuType}}</li>
</ul>
</div>
<div class="sc-goods">
<ul>
<li v-for="(item, index) in goods" :key="index" data-index="index">
<img :class="'goods-image'+index" :src="item.imgSrc" alt="" />
<div class="goods-mes">
<div class="goods-name">{{item.name}}</div>
<div class="goods-description">{{item.description}}</div>
<div class="goods-price"><span>¥</span>{{item.price}}<span class="originalPrice">¥{{item.originalPrice}}</span></div>
<div class="goods-buttons">
<span class="button minus" @click="clickMinus(index)" v-if="item.number !== 0"><img src="../assets/images/shoppingCart/minus.png" alt="" /></span>
<span class="number" v-if="item.number !== 0">{{item.number}}</span>
<span class="button add" @click="clickAdd(index)"><img src="../assets/images/shoppingCart/add.png" alt="" /></span>
</div>
</div>
</li>
</ul>
</div>
</div>
<div class="sc-operation">
<div class="sc-contact">
<img src="../assets/images/shoppingCart/contact.png" alt="" />
<span>联系商家</span>
</div>
<div class="sc-deliveryMes">
<div class="deliveryNumber"><img src="../assets/images/shoppingCart/delivery.png" alt="" /><span v-if="count!==0">{{count}}</span></div>
<div class="priceMes">
<div class="totalPrice">¥{{totalPrice}}<span>¥{{originalTotalPrice}}</span></div>
<div class="deliveryMes">另需配送费¥{{totalDeliveryCost}}<span v-if="totalDeliveryCost !== 0">¥{{totalOriginalDeliveryCost}}</span> 支持自取</div>
</div>
</div>
<div class="sc-pay" @click="clickPay">去结算</div>
</div>
</div>
</template>
<script>
import $ from 'jquery'
export default {
props: {},
data() {
return {
currentIndex: 0, // 当前类型index
menuTypeIndex: 0, // 左边菜单index
goodsList: [{ // 整个商品数据
type: '全部',
menu: [{
menuType: '推荐',
goods: [{
name: '排骨饭套餐',
imgSrc: require('../assets/images/shoppingCart/timg1.jpg'),
description: '物美价廉',
price: 15.50,
originalPrice: 25.36,
number: 0,
deliveryCost: 1,
originalDeliveryCost: 2,
},
{
name: '宫保鸡丁套餐',
imgSrc: require('../assets/images/shoppingCart/timg2.jpg'),
description: '物美价廉',
price: 5.50,
originalPrice: 25.36,
number: 0,
deliveryCost: 2,
originalDeliveryCost: 4,
}
]
}, {
menuType: '折扣',
goods: [{
name: '排骨饭套餐',
imgSrc: require('../assets/images/shoppingCart/timg1.jpg'),
description: '物美价廉',
price: 15.50,
originalPrice: 25.36,
number: 0,
deliveryCost: 1,
originalDeliveryCost: 2,
}]
}]
},
{
type: '好评',
menu: [{
menuType: '推荐',
goods: [{
name: '排骨饭套餐',
imgSrc: require('../assets/images/shoppingCart/timg1.jpg'),
description: '物美价廉',
price: 15.50,
originalPrice: 25.36,
number: 0,
deliveryCost: 1,
originalDeliveryCost: 2,
}]
}]
},
{
type: '买过',
menu: [{
menuType: '推荐',
goods: [{
name: '排骨饭套餐',
imgSrc: require('../assets/images/shoppingCart/timg1.jpg'),
description: '物美价廉',
price: 15.50,
originalPrice: 25.36,
number: 0,
deliveryCost: 1,
originalDeliveryCost: 2,
},
{
name: '宫保鸡丁套餐',
imgSrc: require('../assets/images/shoppingCart/timg2.jpg'),
description: '物美价廉',
price: 5.50,
originalPrice: 25.36,
number: 0,
deliveryCost: 2,
originalDeliveryCost: 4,
}
]
}]
}
],
count: 0, // 总数量
originalTotalPrice: 0, // 原总价
totalPrice: 0, // 总价
totalDeliveryCost: 0, // 优惠后总运费
totalOriginalDeliveryCost: 0, // 总运费
flag: true // 用来判断是否执行动画
}
},
mounted() {},
computed: {
menu() {
return this.goodsList[this.currentIndex].menu;
},
goods() {
return this.menu[this.menuTypeIndex].goods;
}
},
methods: {
toggleType(index) {
this.currentIndex = index;
this.menuTypeIndex = 0; // 默认menu第一个,解决非第一个切换时报错
},
toggleGoods(index) {
this.menuTypeIndex = index;
},
clickMinus(index) {
this.goods[index].number -= 1;
this.count -= 1;
// 价格变化
this.originalTotalPrice -= parseFloat(this.goods[index].originalPrice); // 原总价增加
this.totalPrice -= parseFloat(this.goods[index].price); // 优惠总价增加
this.totalDeliveryCost -= this.goods[index].deliveryCost; // 优惠总配送费增加
this.totalOriginalDeliveryCost -= this.goods[index].originalDeliveryCost; // 优惠总配送费增加
},
clickAdd(index) {
if (this.flag) {
this.flag = false;
this.goods[index].number += 1;
let that = this;
// 动画跳动效果
let count = that.count + 1;
let originalTotalPrice = parseFloat(that.originalTotalPrice) + parseFloat(that.goods[index].originalPrice); // 原总价增加
let totalPrice = parseFloat(that.totalPrice) + parseFloat(that.goods[index].price); // 优惠总价增加
let totalDeliveryCost = that.totalDeliveryCost + that.goods[index].deliveryCost; // 优惠总配送费增加
let totalOriginalDeliveryCost = that.totalOriginalDeliveryCost + that.goods[index].originalDeliveryCost; // 优惠总配送费增加
let $initImg = $('.goods-image' + index); // 被复制的图片对象
let $targetLocation = $('.deliveryNumber img'); // 目标购物车的图片对象
let $moveImg = $initImg.clone().css({ // 生成点击添加行的图片副本,并变成圆形
'position': 'absolute',
'z-index': 99,
'width': $initImg.width() * 0.5,
'height': $initImg.height() * 0.5,
'border-radius': '50%'
}).css($initImg.offset()).appendTo('body'); // 并把位移到图片位置且添加到body
$moveImg
.animate({ // 先匀速向左上
left: $initImg.offset().left - 30,
top: $initImg.offset().top - 50
}, 200, 'linear')
.animate({ // 然后慢慢移到目标位置
left: $targetLocation.offset().left + $targetLocation.width() - $moveImg.width() * 1.5,
top: $targetLocation.offset().top + $targetLocation.height() - $moveImg.height() * 1.5
}, 600, () => {
$moveImg.fadeOut(100, () => { // 最后慢慢消失
$moveImg.detach(); // 删除掉移动对象$moveImg
that.count = count;
// 价格变化
that.originalTotalPrice = originalTotalPrice.toFixed(2);
that.totalPrice = totalPrice.toFixed(2);
that.totalDeliveryCost = totalDeliveryCost;
that.totalOriginalDeliveryCost = totalOriginalDeliveryCost;
this.flag = true;
});
})
};
},
clickPay() {
console.log(this.totalPrice, this.totalDeliveryCost);
}
}
}
</script>
<style lang="less" scoped>
.sc-box {
position: relative;
margin: 20px;
width: 375px;
height: 667px;
background-color: #fff;
.sc-type {
li {
display: inline-block;
background-color: #f5f5f5;
color: #616161;
margin-right: 10px;
height: 32px;
line-height: 32px;
width: 80px;
text-align: center;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
&.active {
background-image: linear-gradient(to right, #fedb39, #febb2e);
color: #000;
font-weight: bold;
}
}
}
.sc-content {
margin-top: 30px;
height: 546px;
display: flex;
overflow-y: auto;
.sc-leftMenu {
height: 100%;
width: 80px;
text-align: center;
background-color: #f5f9fc;
color: #616161;
li {
cursor: pointer;
transition: all 0.3s;
height: 50px;
line-height: 50px;
&.active {
background-color: #fff;
font-weight: bold;
color: #000;
}
}
}
.sc-goods {
margin: 0 10px;
width: 100%;
li {
position: relative;
display: flex;
margin-bottom: 15px;
img {
width: 70px;
height: 70px;
border-radius: 8px;
}
.goods-mes {
margin-left: 8px;
.goods-name {
font-size: 16px;
font-weight: bold;
}
.goods-description {
margin-top: 6px;
color: #616161;
font-size: 12px;
}
.goods-price {
margin-top: 10px;
color: #ff6262;
font-size: 16px;
span {
font-size: 12px;
&.originalPrice {
color: #b4b4b4;
margin-left: 4px;
text-decoration: line-through;
}
}
}
.goods-buttons {
position: absolute;
bottom: 0;
right: 0;
.button {
display: inline-block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
border-radius: 50%;
cursor: pointer;
img {
width: 10px;
height: 10px;
}
}
.minus {
border: 1px solid #d0d0d0;
}
.number {
display: inline-block;
margin: 0 5px;
}
.add {
background-image: linear-gradient(to right, #fedb39, #febb2e);
}
}
}
}
}
}
.sc-operation {
position: absolute;
bottom: 0;
width: 100%;
font-size: 12px;
color: #949494;
display: flex;
.sc-contact {
display: flex;
flex-direction: column;
padding: 10px 10px 10px 15px;
background-color: #000;
border-top-left-radius: 30px;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 30px;
img {
width: 20px;
height: 20px;
margin: 0 auto 3px;
}
}
.sc-deliveryMes {
margin-left: 3px;
padding-right: 15px;
background-color: #000;
display: flex;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
align-items: center;
.deliveryNumber {
position: relative;
img {
position: absolute;
top: -58px;
left: -18px;
width: 100px;
height: 100px;
}
span {
display: inline-block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
border-radius: 50%;
background-color: #ff6262;
color: #fff;
position: absolute;
left: 35px;
top: 0;
}
}
.priceMes {
margin-left: 66px;
.totalPrice {
color: #fff;
font-size: 16px;
margin-bottom: 3px;
span {
color: #949494;
margin-left: 3px;
font-size: 12px;
text-decoration: line-through;
}
}
.deliveryMes {
span {
text-decoration: line-through;
margin: 0 6px 0 3px;
}
}
}
}
.sc-pay {
font-size: 14px;
font-weight: bold;
color: #000;
line-height: 59px;
flex: 1;
text-align: center;
background-image: linear-gradient(to right, #fedb39, #febb2e);
border-top-right-radius: 30px;
border-bottom-right-radius: 30px;
cursor: pointer;
}
}
}
</style>
二. 父组件代码如下(shoppingCartPage.vue),原理分析:
父组件比较简单,主要用来调用子组件。
<template>
<div>
<shopping-cart></shopping-cart>
</div>
</template>
<script>
import ShoppingCart from '../components/shoppingCart'
export default {
components: {
ShoppingCart
},
data() {
return {
}
},
methods: {
}
}
</script>
<style lang="less" scoped>
</style>
更多推荐
所有评论(0)