您好,登錄后才能下訂單哦!
本文實例講述了vue實現(xiàn)購物車拋物線小球動畫效果的方法。分享給大家供大家參考,具體如下:
先上最終效果圖,在商品頁面和商品詳情頁面點擊加號添加商品時都可以看到小球拋物線落入購物車的動畫效果
此文章只寫了商品頁面購物小球的實現(xiàn),商品詳情頁原理類似
實現(xiàn)步驟:
1. 需要三個組件,最下方包含藍色購物車的【購物車】組件shopCart.vue(子組件),每個【加減號】組成的購物小球組件cartControl.vue(子組件),和包含每個商品信息的goods組件goods.vue(父組件)
2. 原理,購物小球組件在點擊加號的時候對外觸發(fā)事件,將小球對象本身傳遞給父組件goods組件,再由goods作為橋梁將這個信息傳遞給另一個子組件shopCart組件,shopCart組件獲取到小球對象后,對該小球進行位置計算,從而實現(xiàn)從不同商品的位置添加商品的拋物線小球效果
3. cartControl.vue部分代碼
html代碼
<div class="cartControl"> <transition name="move"> <!--減少商品--> <div class="decrease " v-show="food.count>0" @click.stop.prevent="decreaseCart"> <span class="inner iconfont"></span> </div> </transition> <!--增加商品--> <div class="count" v-show="food.count>0">{{food.count}}</div> <!--點擊加號按鈕,觸發(fā)事件addCart,將事件對象作為參數(shù)傳遞--> <div class="add iconfont" @click.stop.prevent="addCart($event)"></div> </div>
js代碼
// addCart事件 addCart (event) { if (!event._constructed) return // 檢測事件派發(fā)是否來自于better-scroll if (!this.food.count) { // 當給一個觀測對象添加一個它不存在的屬性的時候,直接賦值是不可以的,需要使用Vue.set設置這個屬性 Vue.set(this.food, 'count', 1) } else { this.food.count++ } this.$emit('cart-add', event.target) // 向父組件觸發(fā)一個自定義的cart-add事件,同時將事件對象傳遞給父組件 },
4. goods.vue部分代碼
html代碼
<!--加減商品--> <div class="cartControl-wrapper"> <!--在父組件監(jiān)聽到子組件觸發(fā)的cart-add事件--> <cart-control :food="food" @cart-add="handlecartAdd"></cart-control> </div>
js代碼 知識點:子組件和父組件之間的數(shù)據(jù)傳遞
_drop (target) { // 在goods.vue定義 _drop方法將cartcontrol的傳遞過來target對象再傳遞給shopCart this.$nextTick(() => { // 使用$nextTick優(yōu)化體驗 this.$refs.shopCart.drop(target) // 父組件goods通過.$refs屬性訪問shopCart子組件的drop方法 }) }, handlecartAdd (target) { // 點擊加號按鈕觸發(fā)事件 this._drop(target) // 調用_drop方法 }
5. shopCart.vue部分代碼
①.定義一個數(shù)組,存放5個小球,這5個小球可以滿足的動畫的運行
②.動畫分為兩層,外層控制小球y軸方向和運動的軌道,內層控制x軸方向的運動
③.使用js動畫鉤子,vue在實現(xiàn)動畫的時候提供了幾個javascript鉤子,可配合css動畫一起使用,也可單獨使用,因為購物車拋物線小球只有進入動畫,沒有離開的動畫,所以enter的鉤子有,before-enter,enter,after-enter,這些鉤子需要在html屬性中聲明,然后在methods中使用這些方法
可參考以下官網(wǎng)
https://cn.vuejs.org/v2/guide/transitions.html#JavaScript-%E9%92%A9%E5%AD%90
④.v-show控制盒子的顯示和隱藏
html
<!--購物車小球--> <div class="ball-container"> <div v-for="(ball,index) of balls" :key="index"> <transition @before-enter="handleBeforeEnter" @enter="handleEnter" @after-enter="handleAfterEnter"> <div class="ball" v-show="ball.show" v-bind:css="false"><!--外層盒子--> <div class="inner inner-hook"></div> <!--內層盒子--> </div> </transition> </div> </div>
data
data () { return { // 使用balls存放5個小球,這些小球的默認狀態(tài)都是不顯示的 balls: [{show: false}, {show: false}, {show: false}, {show: false}, {show: false}], dropBalls: [] // 用dropBalls來存放掉落的小球 } }
在methods中定義方法
// 當觸發(fā)drop方法時小球開始掉落 drop (el) { for (let i = 0; i < this.balls.length; i++) { // 遍歷這5個小球 let ball = this.balls[i] if (!ball.show) { // 當小球顯示狀態(tài)為隱藏時 ball.show = true // 將這個小球的顯示狀態(tài)設置為true ball.el = el // 將cartControl傳過來的對象掛載到ball的el屬性上 this.dropBalls.push(ball) // 將這個小球放入到dropBalls數(shù)組中 return } } }
js動畫
// js動畫鉤子 // beforeenter handleBeforeEnter: function (el) { let count = this.balls.length while (count--) { let ball = this.balls[count] if (ball.show) { let rect = ball.el.getBoundingClientRect() // getBoundingClientRect()獲取小球相對于視窗的位置,屏幕左上角坐標為0,0 let x = rect.left - 32 // 小球x方向位移= 小球距離屏幕左側的距離-外層盒子距離水平的距離 let y = -(window.innerHeight - rect.top - 22) // 負數(shù),因為是從左上角向下 el.style.display = '' el.style.webkitTransform = `translate3d(0,${y}px,0)` // 設置外層盒子,即小球垂直方向的位移 el.style.transform = `translate3d(0,${y}px,0)` let inner = el.getElementsByClassName('inner-hook')[0] inner.style.webkitTransform = `translate3d(${x}px,0,0)` // 設置內層盒子,即小球水平方向的距離 inner.style.transform = `translate3d(${x}px,0,0)` } } }, // enter handleEnter: function (el, done) { /* eslint-disable no-unused-vars */ // 觸發(fā)瀏覽器重繪 let rf = el.offsetHeight this.$nextTick(() => { // 讓動畫效果異步執(zhí)行,提高性能 el.style.webkitTransform = 'translate3d(0, 0, 0)'// 設置小球掉落后最終的位置 el.style.transform = 'translate3d(0, 0, 0)' let inner = el.getElementsByClassName('inner-hook')[0] inner.style.webkitTransform = 'translate3d(0, 0, 0)' inner.style.transform = 'translate3d(0, 0, 0)' el.addEventListener('transitionend', done) // Vue為了知道過渡的完成,必須設置相應的事件監(jiān)聽器。它可以是transitionend或 animationend }) }, handleAfterEnter: function (el) { let ball = this.dropBalls.shift() // 完成一次動畫就刪除一個dropBalls的小球 if (ball) { ball.show = false el.style.display = 'none' } },
希望本文所述對大家vue.js程序設計有所幫助。
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。