微信公众号:二品翻译官
贵有恒何必三更起五更睡,最无益只怕一日曝十日寒!
购物车案例
1、导入、注册、使用Header组件① 安装node_moduels,启动serve服务② App.vue引入Header组件2、基于axios请求列表数据① 安装axios包② 导入axios,定义initCarList函数并进行调用3、只要请求回来的数据,在页面渲染期间要用到,则必须转存到data中4、循环渲染Goods组件① Goods组件封装title、pic、price、state属性② App.vue中渲染Goods组件5、修改商品勾选状态(子传父 自定义事件)① Goods.vue 追加id属性和自定义事件② App.vue接收自定义事件6、定义fullState全选状态① Footer.vue组件② App.vue引入Footer组件7、实现全选功能① Footer.vue 创建fullChange方法② App.vue接收全选状态8、计算商品总价格① Footer.vue追加自定义属性amount② App.vue追加计算属性amt9、把购买数量传给Counter.vue组件① Counter.vue追加自定义num属性② Goods.vue引入Counter.vue组件③ App.vue追加amt计算属性10、修改购买数量并传给App.vue① 在Components下创建eventBus.js② Counter.vue追加ID属性和add方法,同时调用eventBus功能③ App.vue生命周期created中追加bus接收11、动态计算勾选商品数量① Footer.vue追加all自定义属性② APP.vue汇总购买数量
1、导入、注册、使用Header组件
① 安装node_moduels,启动serve服务
E:\Demo\购物车案例\demo-cart> npm cache clear --force
E:\Demo\购物车案例\demo-cart> npm install
E:\Demo\购物车案例\demo-cart> npm run serve
② App.vue引入Header组件
<template>
...
// 引入Header
<Header></Header>
...
</template>
<script>
/* 引入Header */
import Header from '@/components/Header/Header.vue'
export default {
components: {
Header
}
}
</script>
2、基于axios请求列表数据
① 安装axios包
E:\Demo\购物车案例\demo-cart> npm i axios -S
② 导入axios,定义initCarList函数并进行调用
<script>
...
import axios from 'axios'
export default {
methods: {
async initCarList(){
const {data:res} = await axios.get('https://www.escook.cn/api/cart')
console.log(res);
}
},
created() {
this.initCarList();
...
}
</script>
3、只要请求回来的数据,在页面渲染期间要用到,则必须转存到data中
<script>
...
export default {
data(){
return {
list: []
}
},
methods: {
async initCarList(){
const {data:res} = await axios.get('https://www.escook.cn/api/cart')
if(res.status === 200){
this.list = res.list
}
}
},
...
</script>
4、循环渲染Goods组件
① Goods组件封装title、pic、price、state属性
<template>
...
<input type="checkbox" class="custom-control-input" id="cb1" :checked="state" />
<img :src="pic" alt="" />
<h6 class="goods-title">{{title}}</h6>
<span class="goods-price">¥{{price}}</span>
...
</template>
<script>
export default {
props: {
pic: { default: '', type: String, },
title: { default: '', type: String },
price: { default: 0,type: Number},
state: { default: true,type: Boolean}
}
}
</script>
② App.vue中渲染Goods组件
<template>
<div class="app-container">
<Header></Header>
<Goods v-for="item in list" :key="item.id" :pic="item.goods_img" :title="item.goods_name"
:state="item.goods_state" :price="item.goods_price"></Goods>
</div>
</template>
<script>
...
import Goods from '@/components/Goods/Goods.vue'
...
components: {
Header,Goods
}
}
</script>
5、修改商品勾选状态(子传父 自定义事件)
① Goods.vue 追加id属性和自定义事件
<template>
...
// 2、修改id属性 调用自定义changeState事件,复选框本身含有change事件
<input type="checkbox" class="custom-control-input" :id="'cb'+id" :checked="state" @change="changeState"/>
<label class="custom-control-label" :for="'cb'+id">
...
</template>
<script>
export default {
props: {
// 1、追加ID属性
id: {require: true,type: Number},
...
methods: {
// 3、changeState自定义事件
changeState(e){
this.$emit('sendState',{id:this.id,flag:e.target.checked})
}
},
}
</script>
② App.vue接收自定义事件
<template>
<div class="app-container">
// 1、接收自定义事件
<Goods v-for="item in list" :key="item.id" :id="item.id" :pic="item.goods_img"
:title="item.goods_name" :state="item.goods_state" :price="item.goods_price"
@sendState="getState"></Goods>
</div>
</template>
<script>
...
methods: {
...
// 2、创建接收函数
getState(e){
this.list.some(item=>{
if(e.id === item.id){
item.goods_state = e.flag;
return true;
}
})
}
},
...
</script>
6、定义fullState全选状态
① Footer.vue组件
<template>
...
<input type="checkbox" class="custom-control-input" id="cbFull" :checked="isFull" />
<label class="custom-control-label" for="cbFull">全选</label>
...
</template>
<script>
export default {
props: {
isFull: {type: Boolean,default: true}
}
}
</script>
② App.vue引入Footer组件
<template>
...
<Footer :isFull="fullState"></Footer>
...
</template>
<script>
...
/* 4、引入Footer组件 */
import Footer from '@/components/Footer/Footer.vue'
export default {
...
// 通过计算属性 计算是否全选
computed: {
fullState(){
return this.list.every(item=>item.goods_state)
}
},
// 注册Footer组件
components: { Header,Goods,Footer }
}
</script>
7、实现全选功能
① Footer.vue 创建fullChange方法
<template>
...
<input type="checkbox" class="custom-control-input" id="cbFull" :checked="isFull" @change="fullChange"/>
<label class="custom-control-label" for="cbFull">全选</label>
...
</template>
<script>
export default {
....
methods: {
fullChange(e){
this.$emit('sendFullChange',e.target.checked)
}
},
}
</script>
② App.vue接收全选状态
<template>
...
<Footer :isFull="fullState" @sendFullChange="getFullChange"></Footer>
</div>
</template>
<script>
export default {
methods: {
getFullChange(flag){
this.list.forEach(item=>item.goods_state = flag)
}
},
...
</script>
8、计算商品总价格
① Footer.vue追加自定义属性amount
<template>
...
<span class="total-price">¥{{ amount.toFixed(2) }}</span>
...
</template>
<script>
export default {
props: {
amount: {type: Number,default: 0}
},
...
}
</script>
② App.vue追加计算属性amt
<template>
<div class="app-container">
...
<Footer :isFull="fullState" @sendFullChange="getFullChange" :amount="amt"></Footer>
</div>
</template>
<script>
...
export default {
...
computed: {
amt(){
return this.list.filter(item=>item.goods_state).reduce((total,item)=>(total+=item.goods_price*item.goods_count),0)
}
},
...
}
9、把购买数量传给Counter.vue组件
① Counter.vue追加自定义num属性
<template>
...
<!-- 购买的数量 -->
<span class="number-box">{{ num }}</span>
...
</template>
<script>
export default {
props: {
num: {default: 1,type: Number}
}
}
② Goods.vue引入Counter.vue组件
<template>
...
<!-- 商品的数量 -->
<Counter :num="count" :id="id"></Counter>
...
</template>
<script>
import Counter from '@/components/Counter/Counter.vue'
export default {
props: {
...
count: { default: 1,type: Number}
},
components: {
Counter
}
}
</script>
③ App.vue追加amt计算属性
<template>
...
<Footer :isFull="fullState" @sendFullChange="getFullChange" :amount="amt"></Footer>
...
</template>
<script>
...
export default {
...
computed: {
...
amt(){
return this.list.filter(item=>item.goods_state).reduce((total,item)=>(total+=item.goods_price*item.goods_count),0)
}
},
...
</script>
10、修改购买数量并传给App.vue
① 在Components下创建eventBus.js
import Vue from 'vue'
export default new Vue()
② Counter.vue追加ID属性和add方法,同时调用eventBus功能
<template>
...
<button type="button" class="btn btn-light btn-sm" @click="sub">-</button>
<span class="number-box">{{ num }}</span>
<button type="button" class="btn btn-light btn-sm" @click="add">+</button>
</div>
</template>
<script>
import bus from '@/components/eventBus.js'
export default {
props: {
id: {require: true,type: Number},
num: {default: 1,type: Number}
},
methods: {
add(){
bus.$emit('addNum',{id: this.id,value: this.num + 1})
},
sub(){
if(this.num - 1 === 0) return
bus.$emit('addNum',{id: this.id,value: this.num - 1})
}
},
}
</script>
③ App.vue生命周期created中追加bus接收
<script>
...
/* 5、引入eventBus */
import bus from '@/components/eventBus.js'
export default {
...
created() {
bus.$on('addNum',(val)=>{
this.list.some((item)=>{
if(item.id === val.id){
item.goods_count = val.value;
return true;
}
})
})
},
...
}
</script>
11、动态计算勾选商品数量
① Footer.vue追加all自定义属性
<template>
...
<!-- 结算按钮 -->
<button type="button" class="btn btn-primary btn-settle">结算({{ all }})</button>
...
</template>
<script>
export default {
props: {
...
all: {type:Number,default: 0}
},
}
</script>
② APP.vue汇总购买数量
<template>
...
<Footer :isFull="fullState" :all="total" :amount="amt" @sendFullChange="getFullChange" ></Footer>
...
</template>
<script>
...
export default {
...
computed: {
total(){
return this.list.filter(item=>item.goods_state).reduce((total,item)=>(total+=item.goods_count),0)
}
},
}
</script>