Vue實現(xiàn)商品飛入購物車效果(電商項目)
各位掘友,好久不見,最近利用工作之余開源了Vue電商項目,高仿某知名O2O買菜平臺,整個項目做下來收獲還是蠻多的,可以掃描下方二維碼體驗,本篇是項目的核心知識拆解篇,主要是拆解增加商品飛入購物車的實現(xiàn)過程。
首先我先簡單的介紹下本項目所用到的技術(shù)棧:
整個項目采用 vue-cli3 腳手架搭建, Vue全家桶(vue、vuex、vue-router) 、 Vant UI框架 以及很多著名好用的第三方庫如: axios 、 fastclick 、 better-scroll 、 twix.js 、 pubsub.js 、 moment.js 、 vue-amap 等等。 像素單位選擇 rem ,后臺數(shù)據(jù)接口通過 Easy-Mock 搭建,以最接近企業(yè)開發(fā)的方式,組件化模塊化,最大程度實現(xiàn)高內(nèi)聚低耦合,大大提升各模塊的可維護(hù)及可擴(kuò)展性,相信讀完源碼和我寫的系列拆解文章,無論你是哪個段位的攻城獅都會有所啟發(fā)!開源不易,你的點贊就是對我最大的鼓勵:tada::tada:感謝~Thanks♪(・ω・)ノ
二、增加商品飛入購物車實現(xiàn)過程
首先先來瞅瞅要做成的樣子,是不是很炫酷:airplane::airplane:隨手點贊支持下作者:heartbeat:
實現(xiàn)思路
首先我們先來把關(guān)注點放到加入購物車這塊,當(dāng)我們點擊購物車圖標(biāo)的時候,這個時候會在當(dāng)前點擊的商品圖片的中央范圍先出現(xiàn)個圓形的商品縮略圖,其次這個商品縮略圖會沿著當(dāng)前位置以曲線的形式逐漸變小飛入到購物車?yán)?當(dāng)商品飛入到購物車時,購物車的數(shù)字圖標(biāo)會增加,同時購物車會出現(xiàn)彈簧動畫。
通過上面大白話分析整個實現(xiàn)步驟可簡短分為三個階段來完成編碼:
- 第一階段:點擊購物車,出現(xiàn)一個商品縮略圖的小球
- 第二階段:商品縮略小球以曲線形式從當(dāng)前位置飛到底部購物車的位置
- 第三階段:當(dāng)商品縮略小球完全消失在購物車位置時,購物車數(shù)量圖標(biāo)加1,且實現(xiàn)彈簧動畫.
第一階段代碼實現(xiàn)
第一階段編碼:繪制一個圓形的小球到商品的中間區(qū)域 這個非常簡單,就是在商品圖片區(qū)域加一個 div
,設(shè)置 position:fixed
及寬度高度等,但是呢?
先埋個問題,如何讓小球出現(xiàn)在點擊當(dāng)前商品的范圍內(nèi)呢?
階段一踩坑
起初我通過計算屬性遍歷了商品列表,在所有的商品視圖中加入商品縮略圖小球,然后,通過給每個商品列表里增加一個boolean屬性 show
,通過點擊購物車圖標(biāo)來控制我剛創(chuàng)建的小球的顯示與隱藏,然后自己就進(jìn)入了死胡同,饒了半天,計算屬性的數(shù)據(jù)通過 set
方式改變后,Dom死活不聽話就是不按套路出牌(因為計算屬性存在數(shù)據(jù)緩存),于是不得已放棄此笨拙的辦法。
階段一最終實現(xiàn)方案
上面踩坑是因為貪多,想一次性到位,提前加載所有商品的小球縮略圖,然后通過點擊購物車來控制當(dāng)前商品縮略圖的顯示與隱藏.那么我們要不換一種思路,僅創(chuàng)建一個縮略小球怎么樣,通過 boolean
來控制它的顯示和隱藏,位置動態(tài)變化,點擊哪個商品就讓他顯示到哪個商品的范圍內(nèi),并且每次點擊給他設(shè)置個true的屬性丟到一個數(shù)組中.好,我們先在data中定義小球是否顯示的屬性及顯示小球的數(shù)組
data () { return { showMoveDot: [], //控制下落的小圓點顯示隱藏 }
然后我們在點擊購物車的時候來給 showMoveDot
數(shù)組動態(tài)增加屬性,然后在Dom中遍歷這個數(shù)組,雙向綁定,最后通過 v-if
來控制顯示和隱藏,這樣是不是非常妙~~
點擊購物車給 showMoveDot
增加 true
的屬性
methods: { addToCart (product, num) { this.showMoveDot = [...this.showMoveDot, true]; } }
Dom中遍歷 showMoveDot
,并且通過 v-if
來控制商品縮略小球的顯示
<div v-for="(item,index) in showMoveDot" :key="index"> <div class="move_dot" ref="ball" v-if="item"> </div> </div>
此時點擊購物車圖標(biāo)就會在當(dāng)前商品中出現(xiàn)商品縮略圖的小球,至此,階段一大功告成 ✿✿ヽ(°▽°)ノ✿ ~
第二階段代碼實現(xiàn)
本階段需要用到動畫知識,所以首先想到的是Vue的 transition 屬性,首先給縮略圖的小球包一層 transition
并且增加 appear
動畫并且實現(xiàn) beforeEnter
、 afterEnter
事件方法,所以此時修改Dom代碼
<transition appear @before-appear="beforeEnter" @after-appear='afterEnter' v-for="(item,index) in showMoveDot" :key="index.id"> <div class="move_dot" ref="ball" v-if="item"> </div> </transition>
上面Dom代碼的兩個方法 beforeEnter
和 afterEnter
方法分別是動畫初次渲染前和動畫渲染后,那么我們就要把注意點放到這兩個狀態(tài)中. 在初次渲染的時候我們確定下小球的位置,那么這個時候我們就要用到一個方法 getBoundingClientRect ,這個方法返回的是一組矩形的集合,這下就好啦,可以通過這個方法來定位某個元素在屏幕中的位置啦:blush:~
那好,那我們這個時候就成熱打鐵,通過這個方法先來確定點擊購物車圖標(biāo)的時候,購物車這個小圖標(biāo)距左邊和頂部相對屏幕的距離。
定義兩個 data
來接受點擊增加購物車圖標(biāo)獲取到的值.
data () { return { showMoveDot: [], //控制下落的小圓點顯示隱藏 elLeft: 0, //當(dāng)前點擊購物車按鈕在網(wǎng)頁中的絕對top值 elTop: 0, //當(dāng)前點擊購物車按鈕在網(wǎng)頁中的絕對left值 }
然后我們在點擊添加購物車的方法里獲取位置。
methods: { addToCart () { this.showMoveDot = [...this.showMoveDot, true]; this.elLeft = event.target.getBoundingClientRect().left; this.elTop = event.target.getBoundingClientRect().top; } }
此時就獲取到了點擊加入購物車圖標(biāo)的位置啦:v:這個時候離成功進(jìn)了一大半~ 獲取到增加購物車圖標(biāo)的距離后,通過相對位置來確定商品縮略小球的位置,于是在動畫渲染前我們設(shè)置下他的 transform
值,x,y的值自己可以調(diào)整,并且讓他的透明度為0,暫時不顯示.
beforeEnter (el) { // 設(shè)置transform值 el.style.transform = `translate3d(${this.elLeft - 30}px,${this.elTop - 100}px , 0)`; // 設(shè)置透明度 el.style.opacity = 0; },
接下來就是關(guān)鍵,如何讓小球從當(dāng)前位置移動到底部 Tabbar
的購物車中呢?同樣的方法,我們通過 getBoundingClientRect
方法來確定底部Tabbar的購物車徽標(biāo)的 left
和 top
值,獲取到這個值后,就讓小球在當(dāng)前位置,以貝塞爾曲線的方式向購物車x和y的方向移動,當(dāng)移動完成后將數(shù)組 showMoveDot
的屬性設(shè)置為 false
且透明度為1.
在小球繪制完成后的方法中
afterEnter (el) { // 獲取底部購物車徽標(biāo) const badgePosition = document .getElementById("buycar") .getBoundingClientRect(); // 設(shè)置小球移動的位移 el.style.transform = `translate3d(${badgePosition.left + 30}px,${badgePosition.top - 30}px,0)` // 增加貝塞爾曲線 el.style.transition = 'transform .88s cubic-bezier(0.3, -0.25, 0.7, -0.15)'; el.style.transition = 'transform .88s linear'; this.showMoveDot = this.showMoveDot.map(item => false); // 設(shè)置透明度 el.style.opacity = 1; }
此時大功告成!點擊添加購物車按鈕,小球可以曲線飛到購物車中了,來個Gif圖炫耀下✿✿ヽ(°▽°)ノ✿
掘友請留步(╥╯^╰╥)你以為這樣就算完成了嘛~對于Geek:monkey_face:來說,這樣的效果,簡直太Low啦,于是乎,咱們繼續(xù)一起來做個優(yōu)化吧~
階段三 體驗優(yōu)化
優(yōu)化一:把小球變成點擊當(dāng)前商品的圖片
剛開始還真TM把我給難住了,這么多圖片,鬼知道顯示哪個呢?后來靈機(jī)一動,不就是個動態(tài)加載圖片嘛,點擊加入購物車的時候當(dāng)前的商品對象已經(jīng)拿到了,你怕啥,直接取就完啦!~so easy:smile:好,思路有了,那咱就上代碼!
1.在data中追加個 dropImage
屬性.
data () { return { showMoveDot: [], //控制下落的小圓點顯示隱藏 elLeft: 0, //當(dāng)前點擊購物車按鈕在網(wǎng)頁中的絕對top值 elTop: 0, //當(dāng)前點擊購物車按鈕在網(wǎng)頁中的絕對left值 dropImage: '' // 小球圖片 }
2.在Dom中通過動態(tài)綁定的方式來獲取 dropImage
<transition appear @after-appear='afterEnter' @before-appear="beforeEnter" v-for="(item,index) in showMoveDot" :key="index.id"> <div class="move_dot" ref="ball" v-if="item"> <!-- 小球圖片 --> <img :src="dropImage" alt=""> </div> </transition>
3.動態(tài)給 dropImage
賦值
addToCart (product) { // 取出商品的圖片 this.dropImage = product.small_image; // 將商品添加到購物車中 this.ADD_TO_CART(product); // 購物車左邊的 this.elLeft = event.target.getBoundingClientRect().left; this.elTop = event.target.getBoundingClientRect().top; this.showMoveDot = [...this.showMoveDot, true]; },
好啦!此時我們就完成了小球圖片的動態(tài)加載,來個Gif圖炫一哈✿✿ヽ(°▽°)ノ✿
但是有木有發(fā)現(xiàn)個問題,圖片飛過去很突兀,直來直去的,不夠友好,行那咱繼續(xù)優(yōu)化~~
優(yōu)化二:飛入購物車的商品縮略圖逐漸變小
哈哈~讓商品飛入的時候逐漸變小,思來想去,還是用 css3
的 keyframes
來搞比較好,廢話不多說直接上代碼.
1.設(shè)置 keyframes
的值
@keyframes mymove { 0% { transform: scale(1); } 25% { transform: scale(0.8); } 50% { transform: scale(0.6); } 75% { transform: scale(0.4); } 100% { transform: scale(0.2); } }
2.給商品縮略圖添加 animation
并加入 keyframes
img { animation: 0.88s mymove ease-in-out; width: 3rem; height: 3rem; border-radius: 50%; }
好嘞,搞定!來個Gif圖炫一哈✿✿ヽ(°▽°)ノ✿
為啥我覺得還是有點突兀呢,沒辦法,處女座,必須讓他更完美:see_no_evil:
優(yōu)化三:購物車加入商品后彈簧效果
商品縮略小球逐漸變小的落入到購物車中,此時,購物車再來個彈簧效果就更美了,還是老辦法用 css3
的 keyframes
再合適不過啦~
由于Tabbar是用的 Vant
UI組件,在單獨(dú)的 Dashboard.vue
文件中,所以在 Dashboard.vue
文件中給購物車這個圖標(biāo)設(shè)置 keyframes
值.
@keyframes carmove { 0% { transform: scale(1); } 25% { transform: scale(0.8); } 50% { transform: scale(1.1); } 75% { transform: scale(0.9); } 100% { transform: scale(1); } }
并且把這個 keyframes
值設(shè)置給購物車這個圖標(biāo)
.moveToCart { animation: mymove 0.5s ease-in-out; }
購物車的動畫是加完了,但是如何控制小球移入到購物車后讓動畫生效呢?于是先找到小球動畫結(jié)束的方法,通過查資料找到了 transitionend
和 webkitAnimationEnd
兩個方法,于是我對他們做了監(jiān)聽,當(dāng)小球消失的時候在這兩個方法中動態(tài)的增加Tabbar底部購物車的 keyframes
值.
afterEnter (el) { // 監(jiān)聽小球動畫結(jié)束方法 el.addEventListener('transitionend', () => { el.style.display = 'none'; this.listenInCart(); }) // 監(jiān)聽小球動畫結(jié)束方法 el.addEventListener('webkitAnimationEnd', () => { el.style.display = 'none'; this.listenInCart(); }) },
this.listenInCart() 方法是控制底部Tabbar購物車圖標(biāo)動畫的方法,我們已經(jīng)定義了一個class moveToCart ,我采用取巧的辦法,當(dāng)動畫結(jié)束的時候,給Tabbar的購物車添加class moveToCart ,然后讓他在500ms后在移除這個class,這樣就會保證每次增加購物車后,底部Tabbar都會執(zhí)行 keyframs 動畫.
listenInCart () { // 拿到底部Tabbar購物車的DOM元素添加class document.getElementById("buycar").classList.add('moveToCart'); setTimeout(() => { // 500毫秒后移除底部Tabbar購物車的DOM元素class document.getElementById("buycar").classList.remove('moveToCart'); }, 500); }
此時算是真正的大功告成:cherry_blossom:,來個Gif圖炫耀一哈✿✿ヽ(°▽°)ノ✿
都看到這里啦,還不點贊支持下:smile:,鼓勵下作者~ 三、重點來了:rocket::rocket:
我知道掘友們已經(jīng)迫不及待的想看源碼啦~當(dāng)然本篇知識點只是整個項目的冰山一角,還有很多好用好玩的新技術(shù),如 Better-scroll 滾動使用,高德地圖的集成,圖片瀑布流,移動端適配等等主流技術(shù)在這個項目中幾乎都有~放個GitHub連接,掘友們可不要吝嗇手中的小星星哦✿✿ヽ(°▽°)ノ✿
:tada:Vue構(gòu)建大型單頁面電商應(yīng)用 開源啦!點我看源碼:rocket::rocket:
總結(jié)
以上所述是小編給大家介紹的Vue實現(xiàn)商品飛入購物車效果,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!
相關(guān)文章
Vue3項目中配置TypeScript和JavaScript的兼容
在Vue3開發(fā)中,常見的使用JavaScript(JS)編寫代碼,但也會有調(diào)整編寫語言使用TypeScript(TS)的需求,因此,在Vue3項目設(shè)置中兼容TS和JS是刻不容緩的重要任務(wù),2023-08-08基于Vue-Cli 打包自動生成/抽離相關(guān)配置文件的實現(xiàn)方法
基于Vue-cli 項目產(chǎn)品部署,涉及到的交互的地址等配置信息,每次都要重新打包才能生效,極大的降低了效率。這篇文章主要介紹了基于Vue-Cli 打包自動生成/抽離相關(guān)配置文件 ,需要的朋友可以參考下2018-12-12vue elementui表格獲取某行數(shù)據(jù)(slot-scope和selection-change方法使用)
這篇文章主要介紹了vue elementui表格獲取某行數(shù)據(jù)(slot-scope和selection-change方法使用),本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-01-01