Thu May 4 04:34:00 UTC 2023 inscode

上级 9647e8a1
<template>
<!-- 应用程序容器 -->
<div class="app-container">
<!-- 页面头部 -->
<Header title="购物车案例"></Header>
<!-- 页面主体 -->
<!-- <h1>App 根组件</h1> -->
<!-- 商品列表 -->
<Goods v-for="item in list" :key="item.id" :title="item.goods_name" :pic="item.goods_img" :chstate="item.goods_state"
:id="item.id" :price="item.goods_price" :count="item.goods_count" @good_check_change="updateGoodState"></Goods>
<Footer :full_checked="allChecked" :amount="amt" :counts="allCount" @changAllGoodsState="changeState" ></Footer>
<!-- 循环渲染每个商品 -->
<Goods v-for="item in list" :key="item.id" :title="item.goods_name" :pic="item.goods_img" :state="item.goods_state"
:id="item.id" :price="item.goods_price" :count="item.goods_count" @change-state="updateGoodState"></Goods>
<!-- 渲染底部组件 -->
<Footer :checked="allChecked" :total-amount="totalAmount" :total-count="totalCount" @change-all-state="changeAllState"></Footer>
</div>
</template>
<script>
import axios from 'axios' // 导入 axios 模块
import Header from '@/components/Header/Header.vue' // 导入 Header 组件
import Goods from '@/components/Goods/Goods.vue' // 导入 Goods 组件
import Footer from '@/components/Footer/Footer.vue'
import bus from '@/components/eventBus'
import axios from 'axios'; // 引入 axios 模块
import Header from '@/components/Header/Header.vue'; // 引入 Header 组件
import Goods from '@/components/Goods/Goods.vue'; // 引入 Goods 组件
import Footer from '@/components/Footer/Footer.vue'; // 引入 Footer 组件
import eventBus from '@/components/eventBus'; // 引入事件总线实例
export default {
components: {
Header, // 注册 Header 组件
Goods, // 注册 Goods 组件
Header,
Goods,
Footer,
},
data() {
return {
// 初始化 list 数据为空数组
list: []
list: [], // 初始化商品列表为空数组
}
},
methods: {
// 初始化购物车的方法,通过axios发送get请求获取数据
// 初始化购物车数据
async initBuyCars() {
// 发送异步请求获取购物车数据
const { data: res } = await axios.get('https://www.escook.cn/api/cart');
// 判断请求是否成功
if (res.status === 200) {
// 将获取到的数据赋值给组件数据的 list 属性
this.list = res.list;
const { data } = await axios.get('https://www.escook.cn/api/cart'); // 发送 GET 请求获取数据
if (data.status === 200) { // 判断请求是否成功
this.list = data.list; // 将获取到的数据保存到组件的 list 数据中
}
},
// 更新商品状态的方法,接收一个对象作为参数
updateGoodState(e) {
// 遍历组件数据的 list 数组
this.list.some(item => {
// 如果当前遍历到的 item 对象的 id 和传入的参数 e 中的 id 相等
if (item.id === e.id) {
// 将当前遍历到的 item 对象的 goods_state 属性更新为传入的参数 e 中的 state 值
item.goods_state = e.state;
// 返回 true 结束循环
return true;
}
});
// 更新商品状态的方法
updateGoodState({ id, state }) {
const item = this.list.find(item => item.id === id); // 查找到对应 id 的商品
item.goods_state = state; // 更新对应商品的状态
},
// 修改全选状态的方法
changeAllState(state) {
this.list.forEach(item => item.goods_state = state); // 循环遍历每件商品,将其状态改为全选状态
},
changeState(val){
this.list.forEach(item=>item.goods_state=val.value)
}
},
computed:{
allChecked(){
return this.list.every(item=>item.goods_state)
computed: {
// 计算是否全选
allChecked() {
return this.list.every(item => item.goods_state); // 如果每件商品的状态都是已选,则返回 true
},
amt(){
return this.list.filter(item=>item.goods_state).reduce((t,item)=>t+=item.goods_price * item.goods_count,0)
// 计算选中商品的总价
totalAmount() {
return this.list.filter(item => item.goods_state).reduce((total, item) => total = item.goods_price * item.goods_count, 0); // 过滤出已选商品,然后用 reduce 计算商品总价
},
// 计算选中商品的数量
totalCount() {
return this.list.filter(item => item.goods_state).reduce((total, item) => total = item.goods_count, 0); // 过滤出已选商品,然后用 reduce 计算商品数量总和
},
allCount(){
return this.list.filter(item=>item.goods_state).reduce((t,item)=>t+=item.goods_count,0)
}
},
created() {
// 在实例创建之后请求数据
this.initBuyCars()
bus.on('share',val=>{
this.list.some(item=>{
if(item.id===val.id){
item.goods_count = val.value
return true
}
})
})
}
}
// 在组件创建以后,发送请求初始化购物车数据
this.initBuyCars();
// 监听事件总线的 'goods-count-change' 事件,当事件触发时更改对应商品的数量
eventBus.on('goods-count-change', ({ id, value }) => {
const item = this.list.find(item => item.id === id); // 查找到对应 id 的商品
item.goods_count = value; // 更新对应商品的数量
});
},
};
</script>
<style lang="less" scoped>
/* 应用程序容器样式 */
.app-container {
padding-top: 45px;
/* 顶部内边距 */
padding-bottom: 50px;
/* 底部内边距 */
}
</style>
<template>
<div class="number-container d-flex justify-content-center align-items-center">
<!-- 减 1 的按钮 -->
<button type="button" class="btn btn-light btn-sm" @click="sub">-</button>
<button type="button" class="btn btn-light btn-sm" @click="decrement">-</button>
<!-- 购买的数量 -->
<span class="number-box">{{num}}</span>
<span class="number-box">{{ count }}</span>
<!-- 加 1 的按钮 -->
<button type="button" class="btn btn-light btn-sm" @click="add">+</button>
<button type="button" class="btn btn-light btn-sm" @click="increment">+</button>
</div>
</template>
<script>
import bus from '../eventBus' ;
import bus from '../eventBus';
export default {
props:{
num:{
type: Number,
default:1
props: {
count: { // 组件接收的商品数量
type: Number,
default: 1, // 默认为1
},
count_id: { // 组件接收的商品 id
type: Number,
required: true, // 必须传入 id
},
count_id:{
type: Number, // 指定 id 只接受数字类型
required: true, // 指定 id 是必须的,必须传递 id 属性
}
},
methods:{
add(){
bus.emit('share',{id:this.count_id,value:this.num + 1})
methods: {
// 减 1
decrement() {
if (this.count <= 1) return; // 商品数量不能小于 1
bus.emit('goods-count-change', { id: this.count_id, value: this.count - 1 }); // 发送事件,将商品数量减1
},
// 加 1
increment() {
bus.emit('goods-count-change', { id: this.count_id, value: this.count + 1 }); // 发送事件,将商品数量加1
},
sub(){
if (this.num ===1) return
bus.emit('share',{id:this.count_id,value:this.num - 1})
}
},
}
};
</script>
<style lang="less" scoped>
......
......@@ -2,43 +2,42 @@
<div class="footer-container">
<!-- 左侧的全选 -->
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="cbFull" :checked="full_checked" @change="changAppListGoodsSState"/>
<input type="checkbox" class="custom-control-input" id="cbFull" :checked="isChecked" @change="toggleAllGoods"/>
<label class="custom-control-label" for="cbFull">全选</label>
</div>
<!-- 中间的合计 -->
<div>
<span>合计:</span>
<span class="total-price">{{ amount.toFixed(2) }}</span>
<span class="total-price">{{ totalPrice.toFixed(2) }}</span>
</div>
<!-- 结算按钮 -->
<button type="button" class="btn btn-primary btn-settle">结算({{ counts}}</button>
<button type="button" class="btn btn-primary btn-settle">结算({{ totalCheckedCount }}</button>
</div>
</template>
<script>
export default {
props:{
full_checked:{
default:true,
isChecked:{
default: true, // 是否全选默认为 true
type:Boolean,
},
amount:{
totalPrice:{
type:Number,
default:0
default:0 // 默认总价格为 0
},
counts:{
totalCheckedCount:{
type:Number,
default:0
default:0 // 默认选中商品数量为 0
}
},
methods:{
changAppListGoodsSState(e){
this.$emit('changAllGoodsState',{value: e.target.checked})
// 切换所有商品的选中状态
toggleAllGoods(e){
this.$emit('changeAllGoodsState', { value: e.target.checked });
},
}
}
</script>
......
......@@ -4,11 +4,11 @@
<div class="thumb">
<div class="custom-control custom-checkbox">
<!-- 复选框 -->
<input type="checkbox" class="custom-control-input" :id="'cb' + id" :checked="chstate" @change="goodsChecked" />
<input type="checkbox" class="custom-control-input" :id="'cb' + id" :checked="isChecked" @change="toggleGoodsChecked" />
<!-- 将复选框和图片绑定在一起,实现点击图片也可以选中商品 -->
<label class="custom-control-label" :for="'cb' + id">
<!-- 商品的缩略图 -->
<img :src="pic" alt="" />
<img :src="thumbnail" alt="" />
</label>
</div>
</div>
......@@ -18,8 +18,9 @@
<h6 class="goods-title">{{ title }}</h6>
<div class="goods-info-bottom">
<!-- 商品价格 -->
<span class="goods-price">{{price}}</span>
<Counter :num="count" :count_id="id" ></Counter>
<span class="goods-price">{{ price.toFixed(2) }}</span>
<!-- 商品数量 -->
<Counter :count="count" :count_id="id"></Counter>
</div>
</div>
</div>
......@@ -27,10 +28,11 @@
<script>
import Counter from '@/components/Counter/Counter.vue'
export default {
components:{
components: {
Counter,
},
},
props: {
// 商品标题
title: {
......@@ -38,40 +40,41 @@ export default {
default: '商品名称', // 如果没有传入 title,则默认显示 '商品名称'
},
// 商品缩略图
pic: {
type: String, // 指定 pic 只接受字符串类型
default: '', // 如果没有传入 pic,则默认为空字符串
thumbnail: {
type: String, // 指定 thumbnail 只接受字符串类型
default: '', // 如果没有传入 thumbnail,则默认为空字符串
},
// 商品选中状态
chstate: {
type: Boolean, // 指定 chstate 只接受布尔类型
default: true, // 如果没有传入 chstate,则默认为 true
isChecked: {
type: Boolean, // 指定 isChecked 只接受布尔类型
default: true, // 如果没有传入 isChecked,则默认为 true
},
// 商品 ID
id: {
type: Number, // 指定 id 只接受数字类型
required: true, // 指定 id 是必须的,必须传递 id 属性
},
price:{
type: Number,
required: true,
// 商品价格
price: {
type: Number, // 指定 price 只接受数字类型
required: true, // 指定 price 是必须的,必须传递 price 属性
},
// 商品数量
count: {
type: Number,
default: 1,
},
count:{
type: Number,
default:1
}
},
methods: {
// 处理商品选中状态改变的方法
goodsChecked(e) {
// 触发一个自定义事件,将商品 ID 和状态传递给父组件
this.$emit('good_check_change', { id: this.id, state: e.target.checked })
}
}
// 切换商品选中状态
toggleGoodsChecked(e) {
// 触发一个自定义事件,将商品 ID 和选中状态传递给父组件
this.$emit('changeGoodsCheckedState', { id: this.id, isChecked: e.target.checked });
},
},
}
</script>
<style lang="less" scoped>
.goods-container {
border-top: 1px solid #efefef;
......@@ -111,4 +114,5 @@ export default {
}
}
}
}</style>
}
</style>
......@@ -5,11 +5,12 @@
<script>
export default {
props: {
// 标题
title: {
type: String, // 指定 title 只接受字符串类型
default: '标题', // 如果没有传入 title,则默认显示 '标题'
},
}
},
}
</script>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册