Vue实现购物车功能

使用Vue组件完成一个带自动计算、删除、修改、选择、搜索、添加功能的购物车功能

效果预览:

 

步骤:

1.创建子组件:

里面存放的是我们需要传输给购物车的内容,运用父子组件传值(props,$emit)完成传输。

<template id="goods">
		<div class="goods-content" :style="{backgroundColor:(index%2==0?'':'#E2DFDF')}">
			<div class="goods-select">
				<input type="checkbox" v-model="goods.select">
			</div>
			<div class="goods-id">
				<img :src="goods.imgSrc">
			</div>
			<div class="goods-name">
				{{goods.name}}
			</div>
			<div class="goods-price">
				{{goods.price}}
			</div>
			<div class="goods-number">
				<button @click="reduce(index)" style="background-color: #ebcaca;border: #eebbbb;">-</button>
				<input type="text" v-model="goods.number" style="border: none" />
				<button @click="add(index)" style="background-color: #ebcaca;border: #eebbbb;">+</button>
			</div>
			<div class="goods-opt">
				<button @click="del(index)" style="background-color: #ebcaca;border: #eebbbb;">删除</button>
			</div>
		</div>
	</template>
<script type="text/javascript">
		Vue.component( "goods", {
			template: "#goods",
			props: [ "goods", "index" ],
			methods: {
				add ( index )
				{
					this.goods.number++;
					this.$emit( "toupdate", index, this.goods.number );
				},
				reduce ( index )
				{
					if ( this.goods.number > 0 )
					{
						this.goods.number--;
						this.$emit( "toupdate", index, this.goods.number );
					} else
					{
						alert( "数量不能再少了" );
					}
				},
				del ( index )
				{
					this.$emit( 'todel', index );
				}
			}
		} );
</script>

2.页面布局:

简单实现页面效果。

<div id="app">
			<div class="find">
				<input type="text" placeholder="请输入您要查询的物品" id="n" v-model="find">
			</div>
			<div class="form-content">
				<div id="BOX">
					<div id="boxs" v-for="(i,id) in finishs" :key="i.id">
						<img :src="i.imgSrc">
						<p>&nbsp;商品名称:{{i.name}}</p>
						<p>&nbsp;商品价格:{{i.price}}元</p>
						<button type="button" @click="insert(i)">添加至购物车</button>
					</div>
				</div>
			</div>
			<div class="content">
				<h3>购物车</h3>
				<div class="goods-content" style="background-color: #ebcaca;">
					<div class="goods-select">
						选择
					</div>
					<div class="goods-id">
						编号
					</div>
					<div class="goods-name">
						商品名称
					</div>
					<div class="goods-price">
						单价
					</div>
					<div class="goods-number">
						数量
					</div>
					<div class="goods-opt">
						操作
					</div>
				</div>
				<goods v-for="(goods,index) in goodsList" :key="goods.id" :goods="goods" :index="index" @todel="del"
					   @toupdate="update">
				</goods>
				<div id="bl">您的购物车内暂无商品,快去选购吧</div>
				<div id="AllSelect">
					<input type="checkbox" v-model="allCheck" />全选
				</div>
				<div class="total">总价:¥{{total}}元</div>
			</div>
		</div>

3.样式文件:

(此处与页面布局依照自己喜好即可)。

body {
				font-size: 18px;
			}

			.find {
				width: 604px;
				height: 90px;
				margin: 0 auto;
			}

			.find input {
				margin-top: 10px;
				width: 600px;
				height: 40px;
				border: 2px solid #eebbbb;
				border-radius: 25px;
			}

			#BOX {
				width: 1200px;
				margin: 0 auto;
				display: flex;
				flex-wrap: wrap;
				justify-content: space-around;
				font-size: 12px;
			}

			#boxs {
				width: 185px;
				border: 1px solid #eac2c2;
				border-radius: 6px;
			}

			#boxs p {
				padding-left: 10px;
			}

			#boxs img {
				width: 167px;
				height: 150px;
				margin: 4% 5%;
				border-radius: 7px;
			}

			#boxs button {
				margin: 0 18% 4%;
				background-color: #eac2c2;
				border: none;
				height: 35px;
				width: 120px;
				border-radius: 5px;
				font-family: '宋体';
				color: aliceblue;
			}

			.form-content {
				width: 1200px;
				margin: 0 auto;
			}

			.content {
				width: 1200px;
				margin: 0 auto;
				margin-bottom: 70px;
			}

			.goods-content {
				line-height: 60px;
				width: 1200px;
				margin: 0 auto;
				display: flex;
				justify-content: space-between;
			}

			.goods-content div {
				display: inline-block;
				margin-bottom: 1px;
				font-size: 15px;
			}

			.goods-select {
				width: 3%;
				text-align: center;
			}

			.goods-id {
				width: 20%;
				text-align: center;
			}

			.goods-id img {
				width: 100px;
				margin-top: 18px;
			}

			.goods-name {
				width: 37%;
			}

			.goods-price {
				width: 10%;
				text-align: center;
			}

			.goods-number {
				width: 20%;
				text-align: center;
			}

			.goods-opt {
				width: 10%;
				text-align: center;
			}

			.goods-opt button {
				width: 60px;
				height: 30px;
			}

			.goods-content input {
				height: 20px;
				width: 16px;
			}

			.total {
				background: #eac2c2;
				width: 1200px;
				text-align: right;
				margin: 0 auto;
				margin-top: 30px;
				position: fixed;
				bottom: 0;
			}

			#bl {
				width: 1200px;
				margin: 0 auto;
				text-align: center;
				font-size: 30px;
				font-family: '宋体';
				color: #ccc;
			}

			#AllSelect {
				background: #eac2c2;
				width: 1200px;
				margin: 0 auto;
				height: 50px;
				position: fixed;
				bottom: 20px;
			}

4.实现购物车中无商品时显示“您的购物车内暂无商品,快去选购吧”,有商品时文字消失功能:

使用监听属性对购物车数组进行监听,当数组长度为0时,display设置为block,也就是显示样式,当数组长度不为0时,display设置为none,不显示样式。

watch: {
				goodsList ()
				{
					if ( this.goodsList.length !== 0 )
					{
						document.getElementById( 'bl' ).style.display = 'none';
					} else
					{
						document.getElementById( 'bl' ).style.display = 'block';
					}
				}
			}

5.实现加入购物车功能:

使用push()进行对数组元素的添加。

insert ( i )
				{
					if ( this.goodsList == '' )
					{
						this.goodsList.push( i )
					} else
					{
						if ( this.goodsList.includes( i ) )
						{
							var index = this.goodsList.indexOf( i )
							this.goodsList[ index ].number++
						} else
						{
							this.goodsList.push( i )
						}
					}
				}

5.实现删除购物车内容功能:

使用splice()进行对数组元素的删除。

del ( index )
				{
					this.goodsList.splice( index, 1 );
				}

6.实现全选按钮功能:

用every()(用于遍历数组中所有元素,只要有一项不符合要求,便返回false,全符合要求则返回true)实现其他按钮全部被选中时,全选按钮也被选中,用forEach()(用于调用数组的每个元素,并将元素传递给回调函数)实现点击全选按钮其他按钮全部被选中效果。

computed: {
				allCheck: {
					get ()
					{
						if ( this.goodsList.length == 0 )
						{
							select = false;
						} else
						{
							return this.goodsList.every( i => i.select )
						}
					},
					set ( val )
					{
						this.goodsList.forEach( Element =>
						{
							Element.select = val;
						} );
					}
				}
}

7.实现合计计算功能:

对数组进行遍历,如果是选中状态则用数量乘上价格进行相加,未被选中的不参与计算。

computed: {
				total ()
				{
					var money = 0;
					for ( var i = 0; i < this.goodsList.length; i++ )
					{
						if ( this.goodsList[ i ].select == true )
						{
							money += ( parseFloat( this.goodsList[ i ].price ) *
								parseFloat( this.goodsList[ i ].number ) );
						}
					}
					return money;
				}
			}

8.实现搜索框功能:

使用filter()方法过滤数组中元素,indexOf()方法返回指定字符串。

computed: {
				finishs ()
				{
					return this.BoxImg.filter( ( item ) =>
					{
						return item.name.indexOf( this.find ) !== -1
					} )
				}
			}

完整代码:

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>
		<script type="text/javascript" src="js/vue.js"></script>
		<style>
			body {
				font-size: 18px;
			}

			.find {
				width: 604px;
				height: 90px;
				margin: 0 auto;
			}

			.find input {
				margin-top: 10px;
				width: 600px;
				height: 40px;
				border: 2px solid #eebbbb;
				border-radius: 25px;
			}

			#BOX {
				width: 1200px;
				margin: 0 auto;
				display: flex;
				flex-wrap: wrap;
				justify-content: space-around;
				font-size: 12px;
			}

			#boxs {
				width: 185px;
				border: 1px solid #eac2c2;
				border-radius: 6px;
			}

			#boxs p {
				padding-left: 10px;
			}

			#boxs img {
				width: 167px;
				height: 150px;
				margin: 4% 5%;
				border-radius: 7px;
			}

			#boxs button {
				margin: 0 18% 4%;
				background-color: #eac2c2;
				border: none;
				height: 35px;
				width: 120px;
				border-radius: 5px;
				font-family: '宋体';
				color: aliceblue;
			}

			.form-content {
				width: 1200px;
				margin: 0 auto;
			}

			.content {
				width: 1200px;
				margin: 0 auto;
				margin-bottom: 70px;
			}

			.goods-content {
				line-height: 60px;
				width: 1200px;
				margin: 0 auto;
				display: flex;
				justify-content: space-between;
			}

			.goods-content div {
				display: inline-block;
				margin-bottom: 1px;
				font-size: 15px;
			}

			.goods-select {
				width: 3%;
				text-align: center;
			}

			.goods-id {
				width: 20%;
				text-align: center;
			}

			.goods-id img {
				width: 100px;
				margin-top: 18px;
			}

			.goods-name {
				width: 37%;
			}

			.goods-price {
				width: 10%;
				text-align: center;
			}

			.goods-number {
				width: 20%;
				text-align: center;
			}

			.goods-opt {
				width: 10%;
				text-align: center;
			}

			.goods-opt button {
				width: 60px;
				height: 30px;
			}

			.goods-content input {
				height: 20px;
				width: 16px;
			}

			.total {
				background: #eac2c2;
				width: 1200px;
				text-align: right;
				margin: 0 auto;
				margin-top: 30px;
				position: fixed;
				bottom: 0;
			}

			#bl {
				width: 1200px;
				margin: 0 auto;
				text-align: center;
				font-size: 30px;
				font-family: '宋体';
				color: #ccc;
			}

			#AllSelect {
				background: #eac2c2;
				width: 1200px;
				margin: 0 auto;
				height: 50px;
				position: fixed;
				bottom: 20px;
			}
		</style>
	</head>

	<body>
		<div id="app">
			<div class="find">
				<input type="text" placeholder="请输入您要查询的物品" id="n" v-model="find">
			</div>
			<div class="form-content">
				<div id="BOX">
					<div id="boxs" v-for="(i,id) in finishs" :key="i.id">
						<img :src="i.imgSrc">
						<p>&nbsp;商品名称:{{i.name}}</p>
						<p>&nbsp;商品价格:{{i.price}}元</p>
						<button type="button" @click="insert(i)">添加至购物车</button>
					</div>
				</div>
			</div>
			<div class="content">
				<h3>购物车</h3>
				<div class="goods-content" style="background-color: #ebcaca;">
					<div class="goods-select">
						选择
					</div>
					<div class="goods-id">
						编号
					</div>
					<div class="goods-name">
						商品名称
					</div>
					<div class="goods-price">
						单价
					</div>
					<div class="goods-number">
						数量
					</div>
					<div class="goods-opt">
						操作
					</div>
				</div>
				<goods v-for="(goods,index) in goodsList" :key="goods.id" :goods="goods" :index="index" @todel="del"
					   @toupdate="update">
				</goods>
				<div id="bl">您的购物车内暂无商品,快去选购吧</div>
				<div id="AllSelect">
					<input type="checkbox" v-model="allCheck" />全选
				</div>
				<div class="total">总价:¥{{total}}元</div>
			</div>
		</div>
	</body>
	<template id="goods">
		<div class="goods-content" :style="{backgroundColor:(index%2==0?'':'#E2DFDF')}">
			<div class="goods-select">
				<input type="checkbox" v-model="goods.select">
			</div>
			<div class="goods-id">
				<img :src="goods.imgSrc">
			</div>
			<div class="goods-name">
				{{goods.name}}
			</div>
			<div class="goods-price">
				{{goods.price}}
			</div>
			<div class="goods-number">
				<button @click="reduce(index)" style="background-color: #ebcaca;border: #eebbbb;">-</button>
				<input type="text" v-model="goods.number" style="border: none" />
				<button @click="add(index)" style="background-color: #ebcaca;border: #eebbbb;">+</button>
			</div>
			<div class="goods-opt">
				<button @click="del(index)" style="background-color: #ebcaca;border: #eebbbb;">删除</button>
			</div>
		</div>
	</template>
	<script type="text/javascript">
		Vue.component( "goods", {
			template: "#goods",
			props: [ "goods", "index" ],
			methods: {
				add ( index )
				{
					this.goods.number++;
					this.$emit( "toupdate", index, this.goods.number );
				},
				reduce ( index )
				{
					if ( this.goods.number > 0 )
					{
						this.goods.number--;
						this.$emit( "toupdate", index, this.goods.number );
					} else
					{
						alert( "数量不能再少了" );
					}
				},
				del ( index )
				{
					this.$emit( 'todel', index );
				}
			}
		} );
		var vm = new Vue( {
			el: "#app",
			data: {
				goodsList: [],
				BoxImg: [
					{ select: true, id: 1, imgSrc: 'img/1.jpg', price: '8', name: '小毛球袜子黑色', number: '1' },
					{ select: true, id: 2, imgSrc: 'img/2.jpg', price: '8', name: '小毛球袜子紫色', number: '1' },
					{ select: true, id: 3, imgSrc: 'img/3.jpg', price: '8', name: '小毛球袜子玫红色', number: '1' },
					{ select: true, id: 4, imgSrc: 'img/4.jpg', price: '8', name: '小毛球袜子绿色', number: '1' },
					{ select: true, id: 5, imgSrc: 'img/5.jpg', price: '8', name: '小毛球袜子淡粉色', number: '1' },
					{ select: true, id: 6, imgSrc: 'img/6.jpg', price: '8', name: '小毛球白袜子粉球', number: '1' },
					{ select: true, id: 7, imgSrc: 'img/7.jpg', price: '8', name: '小毛球袜子黄色', number: '1' },
					{ select: true, id: 8, imgSrc: 'img/8.jpg', price: '8', name: '小毛球袜子白色', number: '1' },
					{ select: true, id: 9, imgSrc: 'img/9.jpg', price: '6', name: '小白熊袜子黑色', number: '1' },
					{ select: true, id: 10, imgSrc: 'img/10.jpg', price: '7', name: '小翅膀袜子灰色', number: '1' },
					{ select: true, id: 11, imgSrc: 'img/11.jpg', price: '5', name: '小兔子袜子黄色', number: '1' },
					{ select: true, id: 12, imgSrc: 'img/12.jpg', price: '3', name: '小怪物袜子粉色', number: '1' },
					{ select: true, id: 13, imgSrc: 'img/13.jpg', price: '3', name: '小怪物袜子白色', number: '1' },
					{ select: true, id: 14, imgSrc: 'img/14.jpg', price: '3', name: '小怪物袜子绿色', number: '1' },
					{ select: true, id: 15, imgSrc: 'img/15.jpg', price: '3', name: '小怪物袜子卡其色', number: '1' },
					{ select: true, id: 16, imgSrc: 'img/16.jpg', price: '9', name: '小熊猫袜子黑白两色', number: '1' },
					{ select: true, id: 17, imgSrc: 'img/17.jpg', price: '12', name: '大眼睛袜子黑白两色', number: '1' },
					{ select: true, id: 18, imgSrc: 'img/18.jpg', price: '12', name: '大眼睛条纹袜子两色', number: '1' },
				],
				find: ''
			},
			methods: {
				insert ( i )
				{
					if ( this.goodsList == '' )
					{
						this.goodsList.push( i )
					} else
					{
						if ( this.goodsList.includes( i ) )
						{
							var index = this.goodsList.indexOf( i )
							this.goodsList[ index ].number++
						} else
						{
							this.goodsList.push( i )
						}
					}
				},
				update ( index, number )
				{
					this.goodsList[ index ].number = number;
				},
				del ( index )
				{
					this.goodsList.splice( index, 1 );
				},
			},
			computed: {
				allCheck: {
					get ()
					{
						if ( this.goodsList.length == 0 )
						{
							select = false;
						} else
						{
							return this.goodsList.every( i => i.select )
						}
					},
					set ( val )
					{
						this.goodsList.forEach( Element =>
						{
							Element.select = val;
						} );
					}
				},
				total ()
				{
					var money = 0;
					for ( var i = 0; i < this.goodsList.length; i++ )
					{
						if ( this.goodsList[ i ].select == true )
						{
							money += ( parseFloat( this.goodsList[ i ].price ) *
								parseFloat( this.goodsList[ i ].number ) );
						}
					}
					return money;
				},
				finishs ()
				{
					return this.BoxImg.filter( ( item ) =>
					{
						return item.name.indexOf( this.find ) !== -1
					} )
				}
			},
			watch: {
				goodsList ()
				{
					if ( this.goodsList.length !== 0 )
					{
						document.getElementById( 'bl' ).style.display = 'none';
					} else
					{
						document.getElementById( 'bl' ).style.display = 'block';
					}
				}
			},
		} )
	</script>

</html>

  • 16
    点赞
  • 114
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tԅ(¯ㅂ¯ԅ)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值