前端成神之路

vuex购物车的实现具体流程

2018-03-12  本文已影响534人  吴佳浩

过程分析

1.首先购物车弹窗是一个组件,因为会出现在不同的页面中。

2.因为很多组件会用到购物车数据,所以统一放到vuex中。

实现步骤解析

一、加入购物车

将购物车数据统一放在vuex中:

state里放置一个数组:carPanelData,里面放置购物车数据。

// 购物车商品数据state: {    carPanelData: []}

往购物车里push数据:在mutation里面更改state数据。

思路:首先需要将点击加入购物车的每一条数据加一个属性:count,计数,然后将这条点击的商品数据push到state中,当然,首先是需要先用商品ID和state里的商品ID比对,如果没有就push,如果有了,就计数。

以下是代码思路

mutations:    addCarPanelData(state,加入购物车的数据data){//循环carPanelData购物车数据//如果商品ID存在(购物车的id和传进来的ID比对),就设置count++//设置开关false===================================================================        **注意** : 如果上面的条件成立,以下是不执行的,所以可以设置一个开关bOff//如果开关值为true//否则就是商品ID不存在,设置一个新的变量goodsData = 传进来的data;//Vue.set(goodsData,'count',1):为这个变量设置count属性,值为1;//将这个goodsData,push到carPanelData中;              }-------------------------------------------------------------- mutations: {    addCarPanelData (state,data) {letbOff =truestate.carPanelData.forEach((goods) =>{if(goods.sku_id === data.sku_id) {          goods.count++          bOff =false}      })if(bOff) {letgoodsData = data        Vue.set(goodsData,'count',1)        state.carPanelData.push(goodsData)      }console.log(state.carPanelData)    }  }

在商品页选择了商品,点击加入购物车按钮:这时,将这条数据传给vuex,记录到state中(mutation里面已经对该逻辑进行了处理)

要点: 记住vuex的思想,要想改变state,必须提交mutation。

methods:{      addCarPanelHandel(data){//改变state,必须提交mutation,并将此条数据传给vuexthis.$store.commit('addCarPanelData',data)        }}

这时已经基本完成了购物车的逻辑,下面,我们把购物车单独出来做成组件:car-panel。

这个时候就可以把相关数据绑定在购物车了。

要点:如何获取在购物车组件内获取vuex数据?

用computed即可。

//相应的绑定代码=示例{{item.title}})//获取vuex数据computed : {        carPanelData(){returnthis.$store.state.carPanelData        },        count(){returnthis.$store.getters.totleCount        },        totle(){returnthis.$store.getters.totlePrice        }}

最后,对购物车中的商品数量和商品总价计算。

在vue中,我们需要对变量进行进一步处理,可以放在computed里,不建议放在模板中,同样,vuex中,state中的状态如果需要进一步处理,我们可以放入getters.

getters:{// 购物车商品数量计算totleCount (state) {letcount =0state.carPanelData.forEach((goods) =>{        count += goods.count      })returncount    },// 总价格totlePrice (state) {letprice =0state.carPanelData.forEach((goods) =>{        price += goods.price * goods.count      })returnprice    }  }

============================================================

至此,已经完成了加购物车,并且计算数量和金额。

============================================================

二、购物车删除

一开始我的思路是

1、删除数据肯定是要改变state,改变state肯定是需要提交mutation,所以删除的相关逻辑方法应该写在mutation;

2、当时我的问题是如何知晓删除的是哪一条数据?

通过学习,弄清楚了,以后此类需求,都和加入购物和思路是一致的,都是通过对比删除的当前的ID和数据里的所有ID进行比对,就知道是删除具体哪条数据了。

3、那么我需要记住,当前选择的是哪条数据,都是通过在删除的点击方法对应的事件里,参数中传递当前数据(商品ID)即可。这是一个思路,需要牢记

具体实现步骤总结

点击购物车页面的删除商品按钮,绑定一个删除方法,参数传入当前被点击的商品ID,在这个方法里调用mutation里面的删除商品方法:

首先需要循环state的购物车数据;

比对每一项的商品ID是否和当前传入的ID相同,如果是相同的那么就return,不再继续循环了;

在state的购物车数据里删除这项ID相同的数据。

//mutation delCarPanelData (state,id) {      state.carPanelData.forEach((goods,index) => {if(goods.sku_id === id) {          state.carPanelData.splice(index,1)return}      })}//购物车组件中methods: {        delCarPanelHandel(id){            this.$store.commit('delCarPanelData',id)        }}

删除

三、购物车商品数量限制

思路: 这类显示隐藏的案例,都是设置变量属性的ture/false

首先是有一个弹窗组件,当商品数量大于最大值得时候,这个组件需要弹出。

数据中已经有了最大值 : limit_num。

在state中定义一个变量:maxOff :false ,默认不显示,当购物车中商品增加的时候,比对当前商品的数量是否已经大于了limit_num,如果是,就让这个弹窗出来,也就是在mutation中设置该属性为true。

商品数量超过后显示弹窗

// 加入购物车addCarPanelData (state,data) {      state.carPanelData.forEach((goods) =>{if(goods.sku_id === data.sku_id) {          goods.count++          bOff =false//比较当前商品的数量和数据中的商品最大购买数量if(goods.count > goods.limit_num) {            goods.count--            state.maxOff =true}        }      }) }//组件中

computed: {        maxOff(){returnthis.$store.state.maxOff        }  }

关闭弹窗

//mutationsclosePrompt (state) {    state.maxOff =false}//组件中methods : {      closePrompt(){this.$store.commit('closePrompt')      }  }

四、购物车显示隐藏

思路: 一样的,这类显示隐藏,需要设置一个开关,去切换开关即可。

state: {carPanelData: [],maxOff:false,// 弹窗开关carShow :false,// 购物车开关carTimer :null// 购物车定时器},// 购物车显示showCar (state) {      clearTimeout(state.carTimer)      state.carShow =true},// 购物车隐藏hideCar (state) {      state.carTimer = setTimeout(()=>{        state.carShow =false},1000)    }===================//组件中methods: {// 显示购物车showCar(){this.$store.commit('showCar')        },// 隐藏购物车hideCar(){this.$store.commit('hideCar')        } }

四、购物车小球效果

思路:用的vue的transtion钩子函数,原理就是先把小球写死到购物车,点击的时候瞬间移入到需要的位置,然后做一个过渡动画即可,加入贝塞尔曲线。

state: {ball: {// 购物车小球show:false,el:null,// 点击的是哪个购物车按钮img:''}mutations: {// 加入购物车addCarPanelData (state,data) {// 加上这个条件,确保小球飞完再添加if(!state.ball.show) {// 显示购物车state.carShow =trueletbOff =truestate.carPanelData.forEach((goods) =>{// 比对ID,相同就说明购物车已存在此商品,数量增加if(goods.sku_id === data.sku_id) {            goods.count++            bOff =falseif(goods.count > goods.limit_num) {              goods.count--              state.maxOff =truereturn}// 加入购物车,小球显示state.ball.show =truestate.ball.img = data.ali_image// 通过event对象获取到当前点击的按钮state.ball.el = event.path[0]          }        })// 商品不存在,就往数组里新增商品数据if(bOff) {letgoodsData = data          Vue.set(goodsData,'count',1)          state.carPanelData.push(goodsData)// 加入购物车,小球显示state.ball.show =truestate.ball.img = data.ali_image// 通过event对象获取到当前点击的按钮state.ball.el = event.path[0]        }console.log(event)      }    }============//组件内// 小球进入前,初始化beforeEnter(el){// 获取按钮的位置letrect =this.ball.el.getBoundingClientRect()// 获取购物车letrectEl =document.getElementsByClassName('ball-rect')[0].getBoundingClientRect()// 获取小球letball =document.getElementsByClassName('mask-item')[0]//计算按钮和购物车的差值 : 购物车的中心点到左侧的距离 - 按钮中心点到左侧的距离letx = (rectEl.left +16) - (rect.left + rect.width/2)lety = rect.top + rect.height/2- rectEl.top +5-16//计算小球和包着小球的父级的位置ball.style.transform ='translate3d(-'+x+'px,0,0)'el.style.transform ='translate3d(0,'+y+'px,0)'ball.src =this.ball.imgconsole.log(this.ball.img)      },//开始运动enter (el){leta = el.offsetHeight// 获取小球letball =document.getElementsByClassName('mask-item')[0]        el.a = a//避免变量没有使用,eslint报错el.style.transform ="translate3d(0,0,0)"ball.style.transform ="translate3d(0,0,0)"},// 结束,让小球隐藏afterEnter (el){this.ball.show =false}    }===================== .ball-enter-active{    transition: 1s cubic-bezier(.18,1,.94,1)  }  .ball-enter-active .mask-item{    transition: 1s cubic-bezier(0,0,0,0)  }

上一篇下一篇

猜你喜欢

热点阅读