APP
<template> <div class="app-container"> <Heahder></Heahder> <!-- <p>{{fullState}}</p> --> <!-- 循环渲染每一个商品信息 --> <Goods v-for="item in list" :key="item.id" :id="item.id" :title="item.goods_name" :pic="item.goods_img" :price="item.goods_price" :state="item.goods_state" @state-change='getNewState' :count="item.goods_count"> </Goods> <Footer :isfull="fullState" @full-change="getFullState" :amount="amt" :all="total"></Footer> </div> </template> <script> import Footer from './components/Footer/Footer.vue' import axios from 'axios' import Heahder from './components/Header/Header.vue' import Goods from './components/Goods/Goods.vue' import bus from '@/components/eventbus.js' export default { data () { return { //存储购物车列表数据 list : [] } }, created(){ this.initCarList() bus.$on('share',val=>{ this.list.some(item=>{ if(item.id === val.id){ item.goods_count = val.value return true } }) }) }, //计算属性,计算布尔值 computed : { //动态计算全选的状态true false fullState(){ return this.list.every(item=>item.goods_state === true) }, amt () { //计算价先过滤再累加 return this.list.filter(item=>item.goods_state).reduce((total,item)=> total+=item.goods_price*item.goods_count,0) }, //已勾选商品总数量 total(){ return this.list.filter(item=>item.status).reduce((t,item)=>{ return t+=item.goods_count},0) } }, methods : { async initCarList(){ const {data:res} = await axios.get('https://www.escook.cn/api/cart') //请求回来数据在页面渲染需要使用必须转存DATA内 if (res.status === 200) { this.list = res.list } }, //接受子组件传的数据,终止后续循环 getNewState(val){ this.list.some(item=>{ if(item.id === val.id){ item.goods_state = val.value return true } }) }, //接受Footer子组件传递过来的全选按钮状态 getFullState(val){ this.list.forEach(item=>item.goods_state=val) } }, components : {Heahder,Goods,Footer} } </script> <style lang="less" scoped> .app-container { padding-top: 45px; padding-bottom: 50px; } </style>
在components内创建以文件名的文件夹
Counter.vue
<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> <!-- 购买的数量 --> <span class="number-box">{{num}}</span> <!-- 加 1 的按钮 --> <button type="button" class="btn btn-light btn-sm" @click="add">+</button> </div> </template> <script> import bus from '@/components/eventbus.js' export default { props : { //接受到的num数量值 num : { type : Number, default : 1 } }, methods : { add(){ //发送给APP数据格式为{id,value} //其中ID的商品id.value是商品的购买数量 const obj = {id : this.id , value : this.num + 1} //感觉是问题所在 //通过eventbus把obj发给app.vue组件 bus.$emit('share',obj) }, sub(){ if(this.num === 0) return const obj = {id:this.id , value :this.num - 1} //感觉是问题所在 bus.$emit('share',obj) } } } </script> <style lang="less" scoped> .number-box { min-width: 30px; text-align: center; margin: 0 5px; font-size: 12px; } .btn-sm { width: 30px; } </style>
Footer.vue
<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> <!-- 购买的数量 --> <span class="number-box">{{num}}</span> <!-- 加 1 的按钮 --> <button type="button" class="btn btn-light btn-sm" @click="add">+</button> </div> </template> <script> import bus from '@/components/eventbus.js' export default { props : { //接受到的num数量值 num : { type : Number, default : 1 } }, methods : { add(){ //发送给APP数据格式为{id,value} //其中ID的商品id.value是商品的购买数量 const obj = {id : this.id , value : this.num + 1} //感觉是问题所在 //通过eventbus把obj发给app.vue组件 bus.$emit('share',obj) }, sub(){ if(this.num === 0) return const obj = {id:this.id , value :this.num - 1} //感觉是问题所在 bus.$emit('share',obj) } } } </script> <style lang="less" scoped> .number-box { min-width: 30px; text-align: center; margin: 0 5px; font-size: 12px; } .btn-sm { width: 30px; } </style>
Goods.vue
<template> <div class="goods-container"> <!-- 左侧图片 --> <div class="thumb"> <div class="custom-control custom-checkbox"> <!-- 复选框 --> <input type="checkbox" class="custom-control-input" :id="'cb'+id" :checked="state" @change="stateChange"/> <label class="custom-control-label" :for="'cb'+id"> <!-- 商品的缩略图 --> <img :src='pic' alt="" /> </label> </div> </div> <!-- 右侧信息区域 --> <div class="goods-info"> <!-- 商品标题 --> <h6 class="goods-title">{{ title }}</h6> <div class="goods-info-bottom"> <!-- 商品价格 --> <span class="goods-price">{{price}}</span> <!-- 商品的数量 --> <Counter :num="count" :id="id"></Counter> </div> </div> </div> </template> <script> import Counter from '@/components//Counter/Counter.vue' export default { components : {Counter}, //商品的ID //接受商品ID,使用Eventbus方案把数值传递到App.vue的组件,更新哪个商品的数量 props :{ id:{ //必存在 required : true, type : Number }, title : { default : '', type : String }, //渲染商品图片 pic : { default : '', type : String }, //商品单价 price : { default : 0 , type : Number }, //商品勾选状态 state : { default : true, type : Boolean }, count : { type : Number, default : 1 } }, methods : { //只要复选框状态发生了变化,就调用这个函数 stateChange(e){ const newState = e.target.checked //触发自定义事件 this.$emit('state-change',{id:this.id,value:newState }) }, } } </script> <style lang="less" scoped> .goods-container { + .goods-container { border-top: 1px solid #efefef; } padding: 10px; display: flex; .thumb { display: flex; align-items: center; img { width: 100px; height: 100px; margin: 0 10px; } } .goods-info { display: flex; flex-direction: column; justify-content: space-between; flex: 1; .goods-title { font-weight: bold; font-size: 12px; } .goods-info-bottom { display: flex; justify-content: space-between; .goods-price { font-weight: bold; color: red; font-size: 13px; } } } } </style>
Header.vue
<template> <div class="header-container">标题</div> </template> <script> export default {} </script> <style lang="less" scoped> .header-container { font-size: 12px; height: 45px; width: 100%; background-color: #1d7bff; display: flex; justify-content: center; align-items: center; color: #fff; position: fixed; top: 0; z-index: 999; } </style>
因为使用了子传子所以增加组件eventbus.js