過程分析
1.首先購物車彈窗是一個組件,因?yàn)闀霈F(xiàn)在不同的頁面中。
2.因?yàn)楹芏嘟M件會用到購物車數(shù)據(jù)窄刘,所以統(tǒng)一放到vuex中。
實(shí)現(xiàn)步驟解析
一就谜、加入購物車
將購物車數(shù)據(jù)統(tǒng)一放在vuex中:
state里放置一個數(shù)組:carPanelData,里面放置購物車數(shù)據(jù)怪蔑。
// 購物車商品數(shù)據(jù)
state: {? ??
????carPanelData: []
}
往購物車?yán)飌ush數(shù)據(jù):在mutation里面更改state數(shù)據(jù)。
思路:首先需要將點(diǎn)擊加入購物車的每一條數(shù)據(jù)加一個屬性:count,計(jì)數(shù)丧荐,然后將這條點(diǎn)擊的商品數(shù)據(jù)push到state中缆瓣,當(dāng)然,首先是需要先用商品ID和state里的商品ID比對虹统,如果沒有就push弓坞,如果有了,就計(jì)數(shù)车荔。
以下是代碼思路:
mutations:addCarPanelData(state,加入購物車的數(shù)據(jù)data){
//循環(huán)carPanelData購物車數(shù)據(jù)//如果商品ID存在(購物車的id和傳進(jìn)來的ID比對)渡冻,就設(shè)置count++
//設(shè)置開關(guān)false===================================================================? ?**注意** : 如果上面的條件成立,以下是不執(zhí)行的忧便,所以可以設(shè)置一個開關(guān)bOff
//如果開關(guān)值為true//否則就是商品ID不存在族吻,設(shè)置一個新的變量goodsData = 傳進(jìn)來的data;
//Vue.set(goodsData,'count',1):為這個變量設(shè)置count屬性珠增,值為1超歌;
//將這個goodsData,push到carPanelData中蒂教;? ? ? ? ? ? ??
}
mutations: {?
addCarPanelData (state,data) {
let bOff =truestate.carPanelData.forEach((goods) =>{
????????????????????????????????????????if(goods.sku_id === data.sku_id) {? ? ? ? ??
????????????????????????????????????????????????????goods.count++? ? ? ? ?
?????????????????????????????????????????????????????bOff =false
????????????????????????????????????????????}? ? ??
????????????????})
????????if(bOff) {
????????????let goodsData = data? ? ? ??
????????????Vue.set(goodsData,'count',1)? ? ? ??
????????????state.carPanelData.push(goodsData)? ? ??
????????}
????????console.log(state.carPanelData)? ??
????}??
}
在商品頁選擇了商品巍举,點(diǎn)擊加入購物車按鈕:這時,將這條數(shù)據(jù)傳給vuex悴品,記錄到state中(mutation里面已經(jīng)對該邏輯進(jìn)行了處理)
要點(diǎn): 記住vuex的思想禀综,要想改變state,必須提交mutation苔严。
methods:{? ? ??
? ?addCarPanelHandel(data){
????????????????//改變state定枷,必須提交mutation,并將此條數(shù)據(jù)傳給 vuex
????????????????this.$store.commit('addCarPanelData',data)? ? ? ?
?????????}
}
這時已經(jīng)基本完成了購物車的邏輯,下面届氢,我們把購物車單獨(dú)出來做成組件:car-panel欠窒。
這個時候就可以把相關(guān)數(shù)據(jù)綁定在購物車了。
要點(diǎn):如何獲取在購物車組件內(nèi)獲取vuex數(shù)據(jù)退子?
用computed即可岖妄。
//相應(yīng)的綁定代碼=示例{{item.title}})
//獲取vuex數(shù)據(jù)
computed : {? ? ? ??
????????????carPanelData(){
????????????????????return this.$store.state.carPanelData? ? ? ??
????????????},? ? ? ??
????????????count(){
????????????????????????return this.$store.getters.totleCount? ? ? ??
????????????},? ? ? ??
????????????totle(){
????????????????????return? ?this.$store.getters.totlePrice? ? ? ??????
????????????}
}
最后,對購物車中的商品數(shù)量和商品總價計(jì)算寂祥。
在vue中荐虐,我們需要對變量進(jìn)行進(jìn)一步處理,可以放在computed里丸凭,不建議放在模板中福扬,同樣腕铸,vuex中,state中的狀態(tài)如果需要進(jìn)一步處理铛碑,我們可以放入getters.
getters:{
????// 購物車商品數(shù)量計(jì)算
totleCount (state) {
????????let count =0state.carPanelData.forEach((goods) =>{? ? ? ??
????????????????????count += goods.count? ? ??
????????})
????????return? count? ??
},
// 總價格
totlePrice (state) {
????????????let price =0state.carPanelData.forEach((goods) =>{? ? ? ??
????????????????????price += goods.price * goods.count? ? ?
????????????})
? ? ? ? ? ? ? return price? ??
????????}??
}
============================================================
至此狠裹,已經(jīng)完成了加購物車,并且計(jì)算數(shù)量和金額汽烦。
============================================================
二涛菠、購物車刪除
一開始我的思路是:
1、刪除數(shù)據(jù)肯定是要改變state撇吞,改變state肯定是需要提交mutation,所以刪除的相關(guān)邏輯方法應(yīng)該寫在mutation俗冻;
2、當(dāng)時我的問題是如何知曉刪除的是哪一條數(shù)據(jù)梢夯?
通過學(xué)習(xí)言疗,弄清楚了,以后此類需求颂砸,都和加入購物和思路是一致的,都是通過對比刪除的當(dāng)前的ID和數(shù)據(jù)里的所有ID進(jìn)行比對死姚,就知道是刪除具體哪條數(shù)據(jù)了人乓。
3、那么我需要記住都毒,當(dāng)前選擇的是哪條數(shù)據(jù)色罚,都是通過在刪除的點(diǎn)擊方法對應(yīng)的事件里,參數(shù)中傳遞當(dāng)前數(shù)據(jù)(商品ID)即可账劲。這是一個思路戳护,需要牢記。
具體實(shí)現(xiàn)步驟總結(jié):
點(diǎn)擊購物車頁面的刪除商品按鈕瀑焦,綁定一個刪除方法腌且,參數(shù)傳入當(dāng)前被點(diǎn)擊的商品ID,在這個方法里調(diào)用mutation里面的刪除商品方法:
首先需要循環(huán)state的購物車數(shù)據(jù)榛瓮;
比對每一項(xiàng)的商品ID是否和當(dāng)前傳入的ID相同铺董,如果是相同的那么就return,不再繼續(xù)循環(huán)了禀晓;
在state的購物車數(shù)據(jù)里刪除這項(xiàng)ID相同的數(shù)據(jù)精续。
//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)? ? ? ??
????????????????}
}
刪除
三、購物車商品數(shù)量限制
思路: 這類顯示隱藏的案例粹懒,都是設(shè)置變量屬性的ture/false
首先是有一個彈窗組件重付,當(dāng)商品數(shù)量大于最大值得時候,這個組件需要彈出凫乖。
數(shù)據(jù)中已經(jīng)有了最大值 : limit_num确垫。
在state中定義一個變量:maxOff :false ,默認(rèn)不顯示愕把,當(dāng)購物車中商品增加的時候,比對當(dāng)前商品的數(shù)量是否已經(jīng)大于了limit_num森爽,如果是恨豁,就讓這個彈窗出來,也就是在mutation中設(shè)置該屬性為true爬迟。
商品數(shù)量超過后顯示彈窗
// 加入購物車
addCarPanelData (state,data) {? ? ?
?????????????state.carPanelData.forEach((goods) =>{
????????????????????????if(goods.sku_id === data.sku_id) {??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?goods.count++? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?bOff =false? //比較當(dāng)前商品的數(shù)量和數(shù)據(jù)中的商品最大購買數(shù)量? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if(goods.count > goods.limit_num) {? ? ? ? ? ?
?????????????????????????????????????????????????goods.count--? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? state.maxOff =true
????????????????????????????????????}? ? ? ?
?????????????????????????}? ? ??
????????????????})?
}
//組件中
computed: {? ? ? ??
????????????maxOff(){
????????????????return this.$store.state.maxOff? ? ? ??
????????????}??
}
關(guān)閉彈窗
//mutations
????????closePrompt (state) {? ??
?????????????????state.maxOff =false
????????}
//組件中
methods : {? ? ?
?????closePrompt(){
? ? ? ?this.$store.commit('closePrompt')? ? ??
?????}??
?}
四橘蜜、購物車顯示隱藏
思路: 一樣的,這類顯示隱藏付呕,需要設(shè)置一個開關(guān)计福,去切換開關(guān)即可。
state: {
? ? ? ? ?carPanelData: [],
? ? ? ? ? maxOff:false,// 彈窗開關(guān)
? ? ? ? ?carShow :false,// 購物車開關(guān)
? ? ? ? ? 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鉤子函數(shù)象颖,原理就是先把小球?qū)懰赖劫徫镘嚕c(diǎn)擊的時候瞬間移入到需要的位置姆钉,然后做一個過渡動畫即可说订,加入貝塞爾曲線。
state: {
? ? ? ? ? ? ? ? ball: { // 購物車小球
????????????????????????????????show:false,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? el:null,// 點(diǎn)擊的是哪個購物車按鈕
????????????????????????????????????img:''
? ? ? ? ? ? ? }
}
mutations: {
?// 加入購物車
? addCarPanelData (state,data) {
? ? ? ? ? // 加上這個條件潮瓶,確保小球飛完再添加
? ? ? ? ? ?if(!state.ball.show){?
????????????????????// 顯示購物車
? ? ? ? ? ? ? ? ? ? ? state.carShow =true
? ? ? ? ? ? ? ? ? ? ?let bOff =true?
? ? ? ? ? ? ? ? ? ? ? state.carPanelData.forEach((goods) =>{
????????????????????????????// 比對ID陶冷,相同就說明購物車已存在此商品,數(shù)量增加
????????????????????????????if(goods.sku_id===data.sku_id) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? goods.count++
????????????????????????????????????bOff = false?
????????????????????????????????????if(goods.count > goods.limit_num) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????goods.count--
????????????????????????????????????????????state.maxOff = true
????????????????????????????????????????????????????return
? ? ? ? ? ? ? ? ? ? ? ? }?
????????????????????????//加入購物車毯辅, 小球顯示
????????????????????????state.ball.show = true
? ? ? ? ? ? ? ? ? ? ? ? ?state.ball.img = data.ali_image?
? ? ? ? ? ? ? ? ? ? ? ? ? ?// 通過event對象獲取到當(dāng)前點(diǎn)擊的按鈕
????????????????????????????state.ball.el = event.path[0]?
????????????}?
????????})
????????????//商品不存在埂伦, 就往數(shù)組里新增商品數(shù)據(jù)
? ? ? ? ? if(bOff) {
? ? ? ? ? ? ? ? ? ? ? let goodsData = data Vue.set(goodsData, 'count', 1) ????????????????????????state.carPanelData.push(goodsData) // 加入購物車,小球顯示
????????????????????????state.ball.show= true?
????????????????????????state.ball.img = data.ali_image?
????????????????????????// 通過event對象獲取到當(dāng)前點(diǎn)擊的按鈕
????????????????????????state.ball.el = event.path[0]?
????????????????}
????????????console.log(event)?
????}?
}
//組件內(nèi)//
?小球進(jìn)入前, 初始化
beforeEnter(el) {?
????// 獲取按鈕的位置
????let rect =this.ball.el.getBoundingClientRect()
????// 獲取購物車
? ? ?let rectEl =document.getElementsByClassName('ball-rect')[0].getBoundingClientRect()
? ?//獲取小球
????let ball = document.getElementsByClassName('mask-item')[0]?
????//計(jì)算按鈕和購物車的差值 : 購物車的中心點(diǎn)到左側(cè)的距離 - 按鈕中心點(diǎn)到左側(cè)的距離
? ? ? ?let x = (rectEl.left+16) - (rect.left + rect.width / 2)?
? ? ? ?let y = rect.top + rect.height / 2 -rectEl.top + 5 - 16?
????????//計(jì)算小球和包著小球的父級的位置
????????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)
},?
//開始運(yùn)動
enter (el){
????????let a = el.offsetHeight
????????// 獲取小球
????????let ball = document.getElementsByClassName('mask-item')[0]?
????????el.a = a?
? ? ? ? ?//避免變量沒有使用思恐,eslint報(bào)錯
????????el.style.transform ="translate3d(0,0,0)"
????????ball.style.transform= "translate3d(0,0,0)"
},?
// 結(jié)束沾谜,讓小球隱藏
????afterEnter (el){
????????????this.ball.show =false
????}
.ball-enter-active{?
????????????transition:1 s cubic - bezier(.18, 1, .94, 1)
? ? }
.ball - enter - active.mask - item {
? ? ? ? ? ? ? ? ? ? transition: 1 s cubic - bezier(0, 0, 0, 0)
}