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>