vue-购物车

vue购物车, 全部代码, 留存

功能:

1.显示店名+购物记录
2.删除购物记录
3.购物记录对应的小计
4.选中商品的种类数, 数量, 以及总价

组件开发过程思路:

1.整体布局和样式
2.划分独立的功能组件
3.组合所有子组件, 形成整体结构
4.实现组件功能

组件划分:

购物车>店铺对应的购物记录>每条购物记录

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style type="text/css">
		* {
			list-style: none;
			margin: 0;
			padding: 0;
		}
		.item {
		/*
			background-color: yellow;*/
			border: 1px solid;
			padding: 20px;
		}
		.item h2 {
			padding-bottom: 20px;
		}
		.item>ul {
			border: 1px solid;
		}
		.item>ul>li {
			min-height: 100px;
			padding: 20px 10px;
			border: 1px solid;
			position: relative;
		}
		.item>ul>li>span {
			display: inline-block;
		}
		.item>ul>li>span:nth-child(1) {
			width: 60px;
		}
		.item>ul>li>span:nth-child(2) {
			width: 310px;
		}
		.item>ul>li>span:nth-child(3) {
			width: 100px;
		}
		.item>ul>li>span:nth-child(4) {
			width: 150px;
		}
		.item>ul>li>span:nth-child(5) {
			width: 100px;
		}
		.item>ul>li>span:nth-child(6) {
			width: 100px;
		}

		.item>ul>li>span:last-child {
			width: 60px;
			position: relative;
			top: 20px;
		}
		.item>ul>li>span:last-child button{
			background-color: #fff;
			border: none;
			font-weight: 600;
		}
		.item>ul>li>span:last-child button:hover{
			color: #f40;
			border-bottom: 1px solid #f40;
		}
		.item>ul>li>span>span {
		    padding-left: 15px;
		}
		img {
			vertical-align: top;
		}
		.total {
			    background: #ccc;
			    width: 1000px;
			    height: 50px;
			    line-height: 50px;
			    position: fixed;
			    bottom: 0;
			    overflow: hidden;
		}
		.total > .total-btn {
			float: right;
		}

		.total > .total-btn span {
			padding-right: 20px;
		}
		
		.total > .total-btn button {
			background: blue;
			color: white;
			border: none;
			/*padding: 10px 30px;*/
			width: 120px;
			height: 50px;
		}
		
		.item-input input[type="text"] {
			width: 30px;
			text-align: center;
		}
		.item-input button {
			width: 20px;
			height: 20px;
			vertical-align: middle;
			text-align: center;
			background-color: #fff;
			border: none;
			outline: none;
		}
		.header-title {
			color: #3c3c3c;    
			font: 12px/1.5 tahoma,arial,'Hiragino Sans GB','\5b8b\4f53',sans-serif;
			font-weight: 700px;
			height: 50px;
			line-height: 50px;
			background-color: #ccc;
			padding-left: 40px;
		}
		.header-title>span {
			display: inline-block;
		}
		.header-title>span:nth-child(1) {
			width: 60px;
		}
		.header-title>span:nth-child(2) {
			width: 310px;
		}
		.header-title>span:nth-child(3) {
			width: 100px;
		}
		.header-title>span:nth-child(4) {
			width: 150px;
		}
		.header-title>span:nth-child(5) {
			width: 100px;
		}
		.header-title>span:nth-child(6) {
			width: 100px;
		}
		
		#app {
			width: 1000px;
			margin: 0 auto;
		}
	</style>
</head>
<body>
	<!-- <div id="header">
		{{123}}
	</div> -->
	<div id="app">
		<header-title @flag='flag'></header-title>
		<product :init="initData" @del="delet"></product>
	</div>

	<script type="text/javascript" src="vue.js"></script>
	<script type="text/javascript">
		let bus = new Vue({});

		// 标题组件
		Vue.component('header-title', {
			data() {
				return {
					choose: false
				}
			},
			template: `
				<div class="header-title">
					<span>
						<input type="checkbox" id="chooseAll" value="全选" @change="changeAll" v-model="choose"/>
						<label for="chooseAll">全选</label>
					</span>
					<span>商品信息</span>
					<span>单价</span>
					<span>数量</span>
					<span>库存</span>
					<span>金额</span>
					<span>操作</span>
				</div>
			`,
			methods: {
				changeAll() {
					this.$emit('flag', this.choose);
				}
			}
		});
		// 总计组件
		Vue.component('total', {
			props:['initdata'],
			data() {
				return {
					haslist: {},
					showPrice: 0,
					proNum: 0,
					totalPro: 0
				}
			},
			template: `
			<div class="total">
				<div class="total-btn">
					<span>共{{proNum}}种商品, {{totalPro}}件</span>
					<span>总计:{{totalPrice}}</span>
					<button @click="comput">结算</button>
				</div>
			</div>
			`,
			methods: {
				// 计算总价方法
				sum() {
					this.showPrice = 0;
					this.proNum = 0;
					this.totalPro = 0;
					for(let list of this.initdata) {
						if(!list.isShow) {
							continue;
						} else {
							let item = list.chooseitem;
							for(let i of item) {
								if(!i.delete && i.chooseflag) {
									this.showPrice += i.choosenum*i.price;
									this.proNum ++;
									this.totalPro += i.choosenum;
								}
							}
						}
					}
				},
				comput() {
					alert(`成功购买${this.proNum}种商品, 共${this.totalPro}件,\n共计:${this.
						showPrice}元`)
				}
			},
			mounted() {
				// 接收购物车组件的信息
				// bus.$on('send', () => {
				// 	this.sum();
				// });
			}, 
			computed: {
				totalPrice() {
					this.sum();
					return this.showPrice;
				}
			}
		});


		// 总的购物车组件
		Vue.component('product', {
			props: ['init'],
			data() {
				return {
				}
			},
			template: `
			<div>
				<ul>
				<li :key="index" v-for="(item, index) in initdata" v-if="item.isShow">
						<item :itemdata="item" @del="delet"></item>
					</li>
				</ul>
				<total :initdata="init"></total>
			</div>
			`,
			methods: {
				delet(val) {
					// console.log(val)
					this.$emit('del', val);
				}
			},
			computed: {
				initdata() {
					return this.init;
				}
			}
		});

		// 每条购物记录
		Vue.component('item', {
			props: ['itemdata'],
			data() {
				return {
					prolist: {}
				}
			},
			template: `
				<div class="item" >
					<h2>{{item.shopname}}</h2>
					<ul>
						<li v-for="list in item.chooseitem">
						{{item.chooseitem[list]}}
							<span>
								<input type="checkbox" v-model.number="prolist[list.id].chooseflag"/>
							</span>
							<span>
								<img :src="list.src"/>
								<span>{{list.title}}</span>
							</span>
							<span>¥{{prolist[list.id].price}}</span>
							<span class="item-input">
								<button @click="sub(list.id)">-</button>
								<input type="text" v-model.number="prolist[list.id].choosenum"   @change="inputcontrol(list.id)" min="0" :max="list.totalnum"/>
								<button @click.prevent="add(list.id)">+</button>
							</span>
							<span>{{prolist[list.id].totalnum}}</span>
							<span>¥{{prolist[list.id].littotal}}</span>
							<span>
								<ul>
									<li>
										<button @click="deldata(list.id)">删除</button>
									</li>
									<li>
										<button @click="favorite">收藏</button>
									</li>
								</ul>
							</span>
						</li>
					</ul>
				</div>
			`,
			methods: {
				// 初始化购物记录
				init() {
					for(let i in this.item.chooseitem) {
						let item = this.item.chooseitem[i];
						item['littotal'] = item.choosenum * item.price;
						
						this.prolist[item.id] = item;
					}
				},
				// 控制输入的方法
				inputcontrol(index) {
					let reg = /^[0-9]*$/;
					if(!reg.test(this.prolist[index].choosenum)) {
						this.prolist[index].choosenum = 0;
					}	
					if(this.prolist[index].choosenum > this.prolist[index].totalnum) {
						this.prolist[index].choosenum = this.prolist[index].totalnum;
						alert('超出最大库存!');
					} else if(this.prolist[index].choosenum<0) {
						this.prolist[index].choosenum = 0;
						alert('不能为负数!');
					}
				},
				// 添加收藏夹方法
				favorite() {
					alert('加入收藏夹成功!');
				},
				// 删除数据方法
				deldata(index) {
					// this.init()
					// console.log(index)
					this.init();
					this.$emit('del', index);
				},
				// 减少按钮
				sub(index) {
					let item = this.prolist[index];
					if(item.choosenum>0) {
						item.choosenum--;
					}
					item.littotal = item.choosenum*item.price;
					// this.sendnum(index);
				},
				// 增加按钮
				add(index) {
					let item = this.prolist[index];
					if(item.choosenum<item.totalnum) {
						item.choosenum++;
					}
					item.littotal = item.choosenum*item.price;
					// this.sendnum(index);
				},
				// 发送数据到总计组件
				// sendnum(index) {
				// 	let item = this.prolist[index];
				// 	if(item.choosenum>item.totalnum) {
				// 		item.choosenum = item.totalnum;
				// 	}
				// 	bus.$emit('send', index, this.prolist[index]);
				// }
			},
			created() {//初始化
				this.init();
			},
			computed: {
				item() {
					return this.itemdata;
				}
			}
		})

		// 输入框+按钮组
		// Vue.component('item-input', {
		// 	props: ['list', 'index', 'flag'],
		// 	data() {
		// 		return {
		// 			choosenum: this.list.choosenum, //选中数量
		// 		}
		// 	},
		// 	template: `
		// 		<span class="item-input">
		// 			<button @click="sub">-</button>
		// 			<input type="text" :name="list.id" v-model="choosenum"/>
		// 			<button @click.prevent="add">+</button>
		// 			<span>库存: {{list.totalnum}}</span>
		// 			<span>小计: {{littotal}}</span>
		// 		</span>
		// 	`,
		// 	methods: {
		// 		inputcontrol() {
		// 			console.log(123)
		// 			console.log(choosenum)
		// 		},
		// 		// 增加按钮方法
		// 		add() {
		// 			if(this.choosenum<this.list.totalnum){
		// 				this.choosenum ++;
		// 			} else {
		// 				alert("已经是最大库存");
		// 			}
		// 			bus.$emit('lit', this.choosenum * this.list.price , this.list.id, this.flag);
		// 		},
		// 		// 减少按钮方法
		// 		sub() {
		// 			if(this.choosenum>0) {
		// 				this.choosenum --;
		// 			}
		// 			bus.$emit('lit', this.choosenum * this.list.price , this.list.id, this.flag);
		// 		}
		// 	},
		// 	computed: {
		// 		littotal() {
		// 			let lettle = this.choosenum * this.list.price;
					
		// 			return lettle;
		// 		}
		// 	}
		// });


		let vm = new Vue({
			el: '#app',
			data: {
				initData: [
					{
						shopname: '手机店',
						id: 'd1',
						isShow: true,
						chooseitem:[
							{src: './img/android.png', title: '华为', id: 'p1', choosenum: 0, totalnum: 50, price: 1000, chooseflag: false, delete: false},
							{src: './img/android1.png', title: '小米', id: 'p2', choosenum: 0, totalnum: 49, price: 1000, chooseflag: false, delete: false},
							{src: './img/apple.png', title: '苹果', id: 'p3', choosenum: 0, totalnum: 10, price: 1000, chooseflag: false, delete: false},
							{src: './img/apple1.png', title: '三星', id: 'p4', choosenum: 0, totalnum: 15, price: 1000, chooseflag: false, delete: false}
						]
					},
					{
						shopname: '电脑店',
						id: 'd2',
						isShow: true,
						chooseitem:[
							{src: './img/android.png', title: '华为', id: 's1', choosenum: 0, totalnum: 100, price: 1000, chooseflag: false, delete: false},
							{src: './img/android1.png', title: '小米', id: 's2', choosenum: 0, totalnum: 99, price: 1000, chooseflag: false, delete: false}
						]
					},
					{
						shopname: '书店',
						id: 's2',
						isShow: true,
						chooseitem:[
							{src: './img/android.png', title: '红楼梦', id: 'book1', choosenum: 0, totalnum: 100, price: 10},
							{src: './img/android1.png', title: '三国演义', id: 'book2', choosenum: 0, totalnum: 99, price: 80}
						]
					},
					
				]
			},
			methods: {
				// 全选按钮更新数据方法
				flag(val) {
					for(let item in this.initData) {
						for(let list in this.initData[item].chooseitem) {
							let data = this.initData[item].chooseitem[list];
								data.chooseflag = val;
						}
					}
				},
				delet(val) {
					console.log(this.initData)
					for(let item in this.initData) {
						let arr = Array.from(this.initData[item].chooseitem);
						for(let list in this.initData[item].chooseitem) {
							if(this.initData[item].chooseitem[list].id === val) {
								arr.splice(list, 1);
							}
						}
						this.initData[item].chooseitem = arr;
						if(this.initData[item].chooseitem.length === 0) {
							console.log(item)
							this.initData[item].isShow = false;
						}
					}

				}
			}
		});

		// let header = new Vue({
		// 	el: "#header",
		// 	data: {
		// 		test: 123
		// 	}
		// });
	</script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值