一、需要的工具
二、项目目录
三、使用步骤
- 在终端定位到需要创建项目的目录输入
npm init vite-app demo-cart npm install less -D 安装less- 导入bootstrap
npm install axios 安装axiosnpm install mitt 安装mitt
四、项目源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
import { createApp } from 'vue'
import App from './App.vue'
import './assets/css/bootstrap.min.css'
import './index.css'
import axios from 'axios'
import getTotall from './utils/compute.js'
axios.defaults.baseURL = 'https://applet-base-api-t.itheima.net/'
const app = createApp(App)
app.config.globalProperties.$http = axios
app.config.globalProperties.$getTotall = getTotall
app.mount('#app')
- index.css
```css
:root{
font-size: 14px;
}
.custom-checkbox .custom-control-label::before {
border-radius: 10px;
}
<template>
<div class="app-container">
<Header title="我的购物车案例"></Header>
<Goods :goodsList="goodsList" @getNewCount="getNewCount"></Goods>
<Footer :goodsList="goodsList" @getFullSelect="fullSelect"></Footer>
</div>
</template>
<script>
import Header from './components/EsHeader/Header.vue'
import Footer from './components/EsFooter/Footer.vue'
import Goods from './components/EsGoods/Goods.vue'
export default {
name: 'App',
data() {
return { goodsList: [] }
},
created() {
this.getGoodsList()
},
methods: {
async getGoodsList() {
const { data: res } = await this.$http.get('api/cart')
if (res.status == 200) {
console.log(res.message)
this.goodsList = res.list
this.$getTotall(this.goodsList)
} else return console.log('获取购物车的数据失败!')
},
fullSelect(list) {
this.goodsList = list
},
getNewCount(e) {
const findResult = this.goodsList.find(x => x.goods_id === e.goodsId)
if (findResult) {
findResult.goods_count = e.newCount
this.$getTotall(this.goodsList)
}
}
},
components: {
Header,
Footer,
Goods
}
}
</script>
<style lang="less" scoped>
.app-container {
margin-top: 50px;
}
</style>
<template>
<div>
<button @click="countSub">-</button>
<input type="text" v-model.lazy="myCount" />
<button @click="countAdd">+</button>
</div>
</template>
<script>
export default {
name: 'MyCount',
props: {
count: { type: Number, default: 0 },
id: { type: Number, default: 0 }
},
emits: ['getNewCount'],
data() {
return { myCount: this.count, myId: this.id }
},
methods: {
countSub() {
if (this.myCount <= 1) return 0
this.myCount--
this.$emit('getNewCount', { newCount: this.myCount, goodsId: this.myId })
},
countAdd() {
this.myCount++
this.$emit('getNewCount', { newCount: this.myCount, goodsId: this.myId })
}
},
watch: {
myCount(newVal) {
const parseResult = parseInt(newVal)
if (isNaN(newVal) || newVal < 1) {
this.myCount = 1
}
else if (String(newVal).indexOf('.') !== -1) {
this.myCount = parseResult
}
this.$emit('getNewCount', { newCount: this.myCount, goodsId: this.myId })
}
}
}
</script>
<style lang="less" scoped>
input {
width: 25px;
height: 20px;
text-align: center;
line-height: 30px;
outline: none;
margin: 0 5px;
}
button {
border: 0px;
}
</style>
<template>
<div class="footer-container">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="fullSelect" v-model="isFull" @change="isFullSelect" />
<label class="custom-control-label" for="fullSelect">全选</label>
</div>
<div>
合计<span class="totalNum">¥{{ totalPrice }}</span>
</div>
<div class="btn">
<button :disabled="totalNum > 0 ? false : true">结算({{ totalNum }})</button>
</div>
</div>
</template>
<script>
import bus from '../../EventBus/eventBus.js'
export default {
name: 'MyFooter',
props: {
goodsList: {
type: Array,
default: []
}
},
data() {
return {
totalPrice: 0,
totalNum: 0,
isFull: false
}
},
emits: ['getFullSelect'],
methods: {
isFullSelect(e) {
this.goodsList.forEach(x => (x.goods_state = e.target.checked))
this.$emit('getFullSelect', this.goodsList)
this.$getTotall(this.goodsList)
}
},
created() {
bus.on('isfull', val => (this.isFull = val))
bus.on('getTotalCount', val => (this.totalPrice = val))
bus.on('getSum', val => (this.totalNum = val))
}
}
</script>
<style lang="less" scoped>
.footer-container {
width: 100%;
height: 60px;
padding: 10px;
background: #fff;
position: fixed;
bottom: 0;
left: 0;
z-index: 999;
border-top: 1px solid #efefef;
display: flex;
align-items: center;
justify-content: space-between;
.totalNum {
color: #f00;
}
button {
background-color: #00f;
color: #fff;
width: 120px;
height: 40px;
border-radius: 40px;
border: 0px;
}
}
</style>
<template>
<div class="goods-container" v-for="item in goodsList" :key="item.goods_id">
<div class="container-left">
<div class="img">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" :id="item.goods_id" v-model="item.goods_state" @change="checkSelect" />
<label class="custom-control-label" :for="item.goods_id"><img :src="item.goods_img" alt="!" /></label>
</div>
</div>
</div>
<div class="container-right">
<div class="title right-top">
<h5>{{ item.goods_name }}</h5>
</div>
<div class="right-bottom">
<div class="price">¥{{ item.goods_price }}</div>
<div class="count">
<count :count="item.goods_count" :id="item.goods_id" @getNewCount="getCount"></count>
</div>
</div>
</div>
</div>
</template>
<script>
import count from '../EsCount/Count.vue'
import bus from '../../EventBus/eventBus.js'
export default {
name: 'MyGoods',
props: { goodsList: { type: Array, default: [] } },
emits: ['getNewCount'],
components: {
count
},
methods: {
checkSelect() {
this.$getTotall(this.goodsList)
if (this.goodsList.every(x => x.goods_state === true)) {
bus.emit('isfull', true)
} else {
bus.emit('isfull', false)
}
},
getCount(val) {
this.$emit('getNewCount', val)
}
}
}
</script>
<style lang="less" scoped>
.goods-container {
display: flex;
padding: 10px;
border-bottom: 1px solid #efefef;
img {
display: block;
width: 100px;
height: 100px;
}
.container-left {
margin-right: 10px;
}
.container-right {
display: flex;
flex-direction: column;
justify-content: space-between;
flex: 1;
}
.right-bottom {
display: flex;
justify-content: space-between;
align-items: center;
.price {
color: #f00;
}
}
.custom-control-label::before,
.custom-control-label::after {
top: 3.25rem;
}
}
</style>
<template>
<div class="header-container" :style="{ color: fontColor, backgroundColor: bgColor, fontSize: fSize + 'px' }">
<span>{{ title }}</span>
</div>
</template>
<script>
export default {
name: 'MyHeader',
props: {
title: {
type: String,
require: true,
default: '购物车案例'
},
fontColor: {
type: String,
require: true,
default: '#fff'
},
bgColor: {
type: String,
require: true,
default: '#00f'
},
fSize: {
type: Number,
require: true,
default: 16
}
}
}
</script>
<style lang="less" scoped>
.header-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 50px;
line-height: 50px;
text-align: center;
z-index: 999;
}
</style>
import mitt from 'mitt'
const bus = mitt()
export default bus
import bus from '../EventBus/eventBus.js'
export default function getTotall(arr) {
let totalCount = 0
let sum = 0
arr.filter(x => x.goods_state === true).forEach(x => (totalCount += x.goods_price * x.goods_count))
arr.filter(x => x.goods_state === true).forEach(x => (sum += x.goods_count))
bus.emit('getTotalCount', totalCount)
bus.emit('getSum', sum)
}
五、项目地址
demo-cart
|