一、购物车页面绘制

创建vite项目
npm init vite-app item_vite
安装less
npm i less less-loader -D
导入
bootstrap.css
在App.vue中导入头部尾部以及内容区域
<template>
<div id="mater container">
<Head></Head>
<BodyShop :listDate="listDate"></BodyShop>
<FootShop></FootShop>
</div>
</template>
<script>
import Head from "./components/header.vue";
import BodyShop from "./components/body.vue";
import FootShop from "./components/footer.vue";
import bus from "./EventBus/event";
export default {
name: "App",
components: {
Head,
BodyShop,
FootShop,
},
data() {
return {
listDate: [
{
id: 1,
picurl:
"http://img14.360buyimg.com/n7/jfs/t1/28128/7/18573/161061/62e14d6cE1e18d640/3cf8ed57a7dabd5a.jpg",
descript: "女士风衣",
price: "188",
count: 1,
check: true,
},
{
id: 2,
picurl:
"http://img12.360buyimg.com/n2/jfs/t1/29308/30/19373/53535/6308aebdE40f8ccb3/0b7c29e0e1623fdb.jpg",
descript: "女士冲锋衣",
price: "288",
count: 1,
check: false,
},
],
};
},
created() {
bus.on("countChange", (count) => {
console.log("数值发生变化");
});
},
};
</script>
<style lang="less" scoped>
#mater {
height: 500px;
}
</style>
分别创建三个组件
body.vue
<template>
<div class="cart-by-body">
<ul>
<li v-for="item in listDate" :key="item.id">
<div class="picItem">
<div class="left-check">
<label class="radio-inline group_allcheck">
<input type="checkbox" class="inputcheck" v-model="item.check" />
</label>
</div>
<div class="pic">
<img :src="item.picurl" alt="" />
</div>
<div class="right-box">
<div class="top-title">{{ item.descript }}</div>
<div class="bottom-bar">
<div class="price">
¥<span>{{ item.price }}</span>
</div>
<ShopCount class="ev-num"></ShopCount>
</div>
</div>
</div>
</li>
</ul>
</div>
</template>
<script>
import ShopCount from "./shopCountBtn.vue";
export default {
props: {
listDate: {
type: Array,
required: true,
default: [
{
id: 1,
picurl:
"http://img14.360buyimg.com/n7/jfs/t1/28128/7/18573/161061/62e14d6cE1e18d640/3cf8ed57a7dabd5a.jpg",
descript: "女士风衣",
price: "188",
count: 1,
check: true,
},
],
},
},
data() {
return {};
},
components: {
ShopCount,
},
};
</script>
<style lang="less">
.picItem {
margin: 0 auto;
margin-left: 0;
margin-right: 0;
margin-top: 40px;
width: 95%;
height: 100px;
display: flex;
justify-content: space-between;
align-items: center;
.pic {
width: 30%;
height: 100%;
img {
max-width: 100%;
height: 100%;
}
}
}
.left-check {
overflow: hidden;
width: 10%;
.inputcheck {
margin: 0px;
}
}
.right-box {
flex: 1;
height: 100%;
position: relative;
overflow: hidden;
.top-title {
height: 60px;
padding: 0 5px;
text-align: left;
width: 100%;
overflow: hidden;
font-size: 14px;
word-wrap: break-word;
font-weight: 600;
}
.bottom-bar {
height: 40px;
bottom: 0;
left: 0;
padding: 0 5px;
display: flex;
align-items: center;
justify-content: space-between;
.ev-num {
width: 50%;
}
.price {
color: rgb(230, 43, 43);
font-weight: 700;
}
}
}
.group_allcheck {
padding-left: 0px !important;
margin: 0;
}
</style>
footer.vue
<template>
<div class="foot_container">
<div class="box">
<ul>
<li>
<label class="radio-inline group_allcheck">
<input
type="checkbox"
value="全选"
v-model="check"
class="inputcheck"
/>
全选
</label>
</li>
<li>
合计:
<span class="redcolor">¥232.00</span>
</li>
<li>
<button
type="button"
class="btn btn-primary resetbtn"
@clink="submitPrice(totalPrice)"
>
结算(<span>{{ totalPrice }}</span
>)
</button>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: {},
data() {
return {
totalPrice: 55,
check: false,
};
},
methods: {
submitPrice(totalPrice) {
console.log(totalPrice);
},
},
};
</script>
<style lang="less" scoped>
.foot_container {
background-color: #fff;
z-index: 999;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 50px;
text-align: center;
line-height: 50px;
border-top: 1px solid #ccc;
}
.box {
margin: 0 auto;
width: 95%;
font-size: 13px;
ul {
padding: 0;
margin: 0;
display: flex;
justify-content: space-between;
li {
float: left;
height: 50px;
}
}
}
.group_allcheck {
display: flex;
justify-content: space-between;
align-items: center;
.inputcheck {
margin: 0px;
margin-right: 4px;
}
}
.redcolor {
color: rgb(241, 123, 12);
font-weight: 700;
}
.resetbtn {
background: orange;
border: none;
height: 35px;
border-radius: 19px;
font-size: 12px;
}
</style>
header.vue
<!--
* @Author: wangxue 3208230974@qq.com
* @Date: 2022-09-15 16:35:16
* @LastEditors: wangxue 3208230974@qq.com
* @LastEditTime: 2022-09-15 17:57:14
* @FilePath: \code-shopping-car\src\components\header.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div :style="{backgroundColor:bgcolor,color:color,fontSize:fsize+'px'}" class="header_container">{{title}}</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "购物车",
},
color: {
type: String,
default: "white",
},
bgcolor: {
type: String,
default: "#f1bb55",
},
fsize: {
type: Number,
default: "12",
},
},
};
</script>
<style lang="less" scoped>
.header_container{
position: fixed;
z-index: 999;
top: 0;
left: 0;
width: 100%;
height: 40px;
text-align: center;
line-height: 40px;
}
</style>
按钮单独分离一个模板
shopCountBtn.vue
<template>
<div class="numBtn">
<div class="cutBtn btn" @click="cutFn">-</div>
<div class="goodCount">
<span>{{count}}</span>
</div>
<div class="addBtn btn" @click="addFn">+</div>
</div>
</template>
<script>
import bus from "../EventBus/event";
export default {
name: "shopCount",
props: {
goodAccount:{
type: Number,
default:{
account: 1
}
}
},
data() {
return {
count: this.goodAccount.account,
};
},
created(){
},
methods: {
cutFn() {
if (this.count >= 2) {
this.count = this.count - 1;
bus.emit("countChange", this.count);
}
},
addFn() {
this.count = this.count + 1;
bus.emit("countChange", this.count);
},
},
};
</script>
<style scoped lang="less">
.numBtn {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
height: 100%;
.goodCount {
width: 40%;
height: 80%;
border: 1px solid #ccc;
border-radius: 5px;
color: rgb(114, 112, 112);
line-height: 29px;
}
.btn {
width: 30%;
}
}
</style>
功能逻辑实现
全选非全选
//全选功能
updataAlllist(check) {
this.listDate.forEach((v) => (v.check = !check));
},
<template>
<div class="foot_container">
<div class="box">
<ul>
<li>
<label class="radio-inline group_allcheck">
<input
type="checkbox"
value="全选"
v-model="check"
class="inputcheck"
@click="allCheck"
/>
全选
</label>
</li>
<li>
合计:
<span class="redcolor">¥{{totalAmount}}</span>
</li>
<li>
<button
type="button"
class="btn btn-primary resetbtn"
@clink="submitPrice(totalPrice)"
>
结算(<span>{{ goodCount }}</span
>)
</button>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: ["totalAmount","goodCount"],
data() {
return {
check: false,
};
},
emits:["updataAlllist"],
methods: {
submitPrice(totalPrice) {
console.log(totalPrice);
},
//全选功能实现
//修改父元素中的list值
allCheck(){
console.log(this.check)
this.$emit("updataAlllist",this.check)
}
},
};
</script>
<style lang="less" scoped>
.foot_container {
background-color: #fff;
z-index: 999;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 50px;
text-align: center;
line-height: 50px;
border-top: 1px solid #ccc;
}
.box {
margin: 0 auto;
width: 95%;
font-size: 13px;
ul {
padding: 0;
margin: 0;
display: flex;
justify-content: space-between;
li {
float: left;
height: 50px;
}
}
}
.group_allcheck {
display: flex;
justify-content: space-between;
align-items: center;
.inputcheck {
margin: 0px;
margin-right: 4px;
}
}
.redcolor {
color: rgb(241, 123, 12);
font-weight: 700;
}
.resetbtn {
background: orange;
border: none;
height: 35px;
border-radius: 19px;
font-size: 12px;
}
</style>
总额
totalprice() {
var total = 0;
this.listDate.forEach((v) => {
if (v.check) {
total = v.price * v.count + total;
}
});
return total;
},
商品选择数量
goodNum() {
var total = 0;
this.listDate.forEach((v) => {
if (v.check) {
total = total + 1;
}
});
this.goodNum= total;
return total;
},
eventBus更改count值
created() {
bus.on("countChange", (map) => {
console.log(map.goodId)
this.listDate.forEach((v) => {
if(v.id==map.goodId){
this.listDate[map.goodId-1].count= map.goodCount
// map.goodCount
}
});
});
},

商品管理
ui绘制
header
<template>
<div
:style="{ backgroundColor: bgcolor, color: color, fontSize: fsize + 'px' }"
class="header_container"
>
<span>{{ title }}</span
><button v-if="openManage" type="button" class="btn btn-warning manage" @click="manageBtnFn" >
完成
</button>
<button v-else type="button" class="btn btn-warning manage" @click="manageBtnFn" >
管理
</button>
</div>
</template>
<script>
import bus from "../EventBus/event";
export default {
data(){
return {
openManage:false
};
},
methods: {
manageBtnFn() {
this.openManage = !this.openManage;
bus.emit("changeManageBtn", this.openManage);
},
},
props: {
title: {
type: String,
default: "购物车",
},
color: {
type: String,
default: "white",
},
bgcolor: {
type: String,
default: "#f1bb55",
},
fsize: {
type: Number,
default: "12",
},
},
};
</script>
<style lang="less" scoped>
.header_container {
position: fixed;
z-index: 999;
top: 0;
left: 0;
width: 100%;
height: 40px;
text-align: center;
line-height: 40px;
.manage {
position: absolute;
margin-right: 7px;
margin-top: 7px;
right: 0;
height: 26px;
border: none;
border-radius: 20px;
font-size: 12px;
background-color: #f1bb55;
&:hover {
background-color: #ec971f;
}
}
}
</style>
footer
<template>
<div class="foot_container">
<div class="box">
<ul>
<li>
<label class="radio-inline group_allcheck">
<input
type="checkbox"
value="全选"
v-model="check"
class="inputcheck"
@click="allCheck"
/>
全选
</label>
</li>
<li v-show="!controlDel">
合计:
<span class="redcolor">¥{{ totalAmount }}</span>
</li>
<li v-show="controlDel">
<button type="button" class="btn btn-warning delBtn">删除</button>
</li>
<li v-show="!controlDel">
<button
type="button"
class="btn btn-primary resetbtn"
@click="submitPrice"
>
结算(<span>{{ goodCount }}</span
>)
</button>
</li>
</ul>
</div>
</div>
</template>
<script>
import bus from "../EventBus/event";
export default {
props: ["totalAmount", "goodCount"],
data() {
return {
check: false,
controlDel: false,
};
},
created() {
bus.on("changeManageBtn", (v) => {
this.controlDel = v;
});
},
emits: ["updataAlllist"],
methods: {
submitPrice() {
console.log(this.totalAmount);
if (this.totalAmount == 0 || this.totalAmount == "") {
alert("请选择商品");
} else {
alert("当前支付金额为" + this.totalAmount);
}
},
//全选功能实现
//修改父元素中的list值
allCheck() {
console.log(this.check);
this.$emit("updataAlllist", this.check);
},
},
};
</script>
<style lang="less" scoped>
.foot_container {
background-color: #fff;
z-index: 999;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 50px;
text-align: center;
line-height: 50px;
border-top: 1px solid #ccc;
}
.box {
margin: 0 auto;
width: 95%;
font-size: 13px;
ul {
padding: 0;
margin: 0;
display: flex;
justify-content: space-between;
li {
float: left;
height: 50px;
}
.delBtn {
width: 100px;
}
}
}
.group_allcheck {
display: flex;
justify-content: space-between;
align-items: center;
.inputcheck {
margin: 0px;
margin-right: 4px;
}
}
.redcolor {
color: rgb(241, 123, 12);
font-weight: 700;
}
.resetbtn {
background: #f0ad4e;
border: none;
height: 35px;
border-radius: 19px;
font-size: 12px;
}
</style>
进阶版
使用在线api以及more,filter优化
<template>
<div>
<Head></Head>
<BodyShop :listDate="list"></BodyShop>
<FootShop
@delGoodlist="delList"
@updataAlllist="updataAlllist"
:totalAmount="totalprice"
:goodCount="goodNum"
:isFull="fullState"
></FootShop>
</div>
</template>
<script>
import axios from "axios";
import Head from "./components/header.vue";
import BodyShop from "./components/body.vue";
import FootShop from "./components/footer.vue";
import bus from "./EventBus/event";
export default {
name: "App",
components: {
Head,
BodyShop,
FootShop,
},
data() {
return {
totalprice: 0,
goodNum: 0,
list: [],
fullState: false,
};
},
created() {
this.initCartList();
bus.on("countChange", (map) => {
this.list.some((v) => {
if (v.id == map.goodId) {
this.list[v.id - 1].goods_count = map.goodCount;
}
});
// this.list.forEach((v) => {
// if (v.id == map.goodId) {
// this.list[v.id - 1].goods_count = map.goodCount;
// }
// });
});
},
methods: {
async initCartList() {
const { data: res } = await axios.get("https://www.escook.cn/api/cart");
if (res.status === 200) {
this.list = res.list;
}
},
//全选功能
updataAlllist(check) {
this.list.forEach((v) => (v.goods_state = !check));
},
delList() {},
},
computed: {
totalprice() {
return this.list
.filter((item) => item.goods_state)
.reduce((t, item) => (t += item.goods_price * item.goods_count), 0);
// var total = 0;
// this.list.forEach((v) => {
// if (v.goods_state) {
// total = v.goods_price * v.goods_count + total;
// }
// });
// return total;
},
//是否是全选状态
fullState() {
return this.list.every((item) => item.goods_state === true);
},
goodNum() {
return this.list
.filter((item) => item.goods_state)
.reduce((t, item) => (t += item.goods_count), 0);
},
},
};
</script>
<style lang="less" scoped></style>
版权声明:本文为qq_43547255原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。