vue综合案例——Vue购物车
程序员文章站
2022-07-04 19:33:13
...
vue综合案例:购物车
css文件:
.container {
margin: auto;
width: 1200px;
}
.container .cart {
width: 1200px;
}
.container .title {
background-color: lightblue;
height: 40px;
line-height: 40px;
text-align: center;
/*color: #fff;*/
}
.container .total {
background-color: #ccc;
height: 50px;
line-height: 50px;
text-align: right;
}
.container .total button {
margin: 0 10px;
background-color: seagreen;
height: 35px;
width: 80px;
border: 0;
outline: none;
cursor: pointer;
}
.container .total span {
color: red;
font-weight: bold;
}
.container .item {
height: 55px;
line-height: 55px;
position: relative;
border-top: 1px solid #ADD8E6;
padding-left: 20px;
}
.container .item img {
width: 45px;
height: 45px;
margin: 5px;
}
.container .item .name {
position: absolute;
width: 90px;
top: 0;
left: 100px;
font-size: 16px;
}
.container .item .price {
position: absolute;
width: 90px;
top: 0;
left: 300px;
}
.container .item .change {
width: 100px;
position: absolute;
top: 0;
right: 100px;
}
.container .item .change a {
font-size: 20px;
width: 30px;
text-decoration: none;
background-color: lightgray;
vertical-align: middle;
}
.container .item .change .num {
width: 40px;
height: 25px;
text-align: center;
}
.container .item .del {
position: absolute;
top: 0;
right: 0px;
width: 40px;
text-align: center;
font-size: 40px;
cursor: pointer;
color: red;
}
.container .item .del:hover {
background-color: #ccc;
}
主要代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>购物车</title>
<script src="../js/vue.js"></script>
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<div id="app">
<cart>
</cart>
</div>
<script>
// 标题组件
let heading = {
// data() {
// // 用retrun返回一个对象,数据最好不写在子组件里面,放父组件里面
// return {
// userName: "张三"
// }
// },
// uname:自定义的属性名
props: ["uname"],
template: `
<div class="title">{{uname}}的商品</div>
`
}
// 商品列表组件
let goodsList = {
props: ["list"],
// 因为list是数组,所以要以数组方式取值
// 单价是input,所以需要双向绑定
// 子组件用点击事件@click来触发传送数据的事件del(),传item.id过去
template: `
<div>
<div class="item" v-for="item in list">
<div class="id">{{item.id}}</div>
<div class="name">{{item.name}}</div>
<div class="price">{{item.price}}</div>
<div class="change">
<a href="" @click.prevent="sub(item.id)">-</a>
<input type="text" class="num" :value="item.num" @blur="changNum(item.id,$event)"/>
<a href="" @click.prevent="add(item.id)">+</a>
</div>
<div class="del" @click="del(item.id)">×</div>
</div>
</div>
`,
// 子向父传值,需要用$emit()事件触发自定义事件,来触发父组件接收数据的方法
methods: {
del(id) {
this.$emit("del", id);
},
// e为当前的事件对象
changNum(id, e) {
// 当前对象的id
// console.log(id);
// e.target为对应的表单域
// e.target.value获取当前表单的value
// console.log(e.target.value);
this.$emit("editNum", [id, e.target.value])
},
// 加、减法都是跟处理数量有关,所以都要传值,都触及到父组件处理数量的方法editNum,用到$emit("editNum")
// 这里值传id,找到相应的对象,再进行处理即可
sub(id) {
// console.log(id);
// "sub"作为标记,editNum判断是哪个事件
this.$emit("editNum", [id, "sub"]);
},
add(id) {
// "add"作为标记
this.$emit("editNum", [id, "add"]);
}
}
}
// 结算组件
let total = {
props: ["list"],
template: `
<div class="total">
<span>总价:{{total}}</span>
<button>结算</button>
</div>
`,
computed: {
// 这里用到list,所以也要接收从父组件传来的数据
total() {
var sum = 0;
// this.list.forEach(function (v) {
// console.log(v);
// });
this.list.forEach(function (item) {
sum += item.price * item.num;
});
return sum;
}
}
}
Vue.component("cart", {
// 子组件所需数据放父组件里面
data() {
return {
userName: "张三",
list: [{
id: 1,
name: 'TCL彩电',
price: 1000,
num: 2,
}, {
id: 2,
name: '机顶盒',
price: 1000,
num: 1,
}, {
id: 3,
name: '海尔冰箱',
price: 1000,
num: 1,
}, {
id: 4,
name: '小米手机',
price: 1000,
num: 1,
}, {
id: 5,
name: 'PPTV电视',
price: 1000,
num: 2,
}]
}
},
// 使用三个局部组件
// 父传子,uname、list:自定义属性名,userName、list是父组件的数据名
// 子传父:自定义一个事件@del,来触发父组件接收数据的一个方法delGoods($event),$event是固定的,不能改
template: `
<div class="container">
<heading :uname="userName"></heading>
<goodsList :list="list" @del="delGoods($event)" @editNum="editNum($event)"></goodsList>
<total :list="list"></total>
</div>
`,
methods: {
// 删除
delGoods(data) {
// filter:结果为true的,进入新数组,为false的淘汰,不会影响原数组
// 传过来的数据data与原数组的id进行对比,不一样的会进入新数组,返回新数组
// this.list = this.list.filter((v) => {
// v为原数组list
// return v.id !== data;
// })
this.list = this.list.filter((v) => v.id !== data);
},
// 改变单价,总额跟着一起改变
editNum(data) {
// console.log(data);
// 判断data[1] === "sub",则为减法,进行处理
// data[1] === "add",则为加法
// 都不是则为失去焦点事件
if (data[1] === "sub") {
var id = data[0];
var data = this.list.find((v) => v.id === id)
if (data.num > 1) {
data.num--;
} else {
alert("不能少于1")
}
} else if (data[1] === "add") {
var id = data[0];
var data = this.list.find((v) => v.id === id)
data.num++;
} else {
// 这里是失去焦点事件
// 这里的data是传送过来的id和数量[]
// console.log(data);
id = data[0];
num = data[1];
// v是父组件中的data,v.id是list中的id,id是传过来的id
// find():查找list中的id与传过来的id
var data = this.list.find((v) => v.id === id);
// 这里的data为传过来的id与list中的id符合的那条数据(对象)
// console.log(data);
// 重新赋值
data.id = id;
// 失去焦点后,用新的数据去进行计算
data.num = num;
}
}
},
// 这三个是局部组件,只能在cart里面使用
components: {
heading,
goodsList,
total
}
})
let vm = new Vue({
el: "#app",
});
</script>
</body>
</html>
上一篇: Vue-记事本综合案例