標籤:org cli 通過 osi can [] any 組件 guide
http://www.cnblogs.com/yuxingyoucan/p/7063881.html
產生一個動畫小球的div,並且產生五個小球,五個是為了產生一定數量的小球來作為操作使用,按照小球動畫的速度,一般來說五個也可以保證有足夠的小球數量來運行動畫
動畫的內容分別是外層和內層,外層控制動畫小球的軌道和方向,內層控制動畫小球的運行狀態
動畫使用vue的js鉤子實現
因為小球動畫只有一個方向(只執行單方向從上到下滾落),所以只用了before-enter,enter,after-enter
用v-show控制小球的可見度,在動畫執行期間可見,其餘時候隱藏
<div class="ball-container"> <transition name="fade" v-for="ball in balls" :key="ball" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"> <div class="ball" v-show="ball.show"> <div class="inner inner-hook"></div> </div> </transition> </div>
-
設定了balls數組來代表五個小球
設定了dropBalls數組正在啟動並執行小球
data(){ return { balls: [ { show: false }, { show: false }, { show: false }, { show: false }, { show: false } ], dropBalls:[] } },
-
-
只要觸發了drop事件,不止是drop事件裡面的代碼會執行,另外幾個vue的js監聽鉤子也會一起按順序執行
觸發了drop事件
beforeEnter開始執行
enter開始執行
afterEnter開始執行
drop事件的觸發可以通過點擊cartcontrol組件的添加小球按鈕addCart事件觸發使用$emit,也可以父組件this.$refs.shopcart.drop(target);直接觸發
這麼做的目的是實現,在子組件cartcontrol點擊之後,可以將該dom傳給父組件goods然後再傳給子組件shopcart,(因為目前他們之間的通道就是這樣,shopcart子組件並沒有匯入cartcontrol子組件,所以沒有直接通訊)這樣就實現了多個組件之間的通訊,從而可以實現需求,例如這裡就是實現點擊子組件cartcontrol後添加一個動畫,將小球滑落到另外一個組件shopcart
$emit是觸發當前執行個體上的事件。附加參數都會傳給監聽器回調。
methods: { drop(el) { //觸發一次事件就會將所有小球進行遍曆 for (let i = 0; i < this.balls.length; i++) { let ball = this.balls[i]; if (!ball.show) { //將false的小球放到dropBalls ball.show = true; ball.el = el; //設定小球的el屬性為一個dom對象 this.dropBalls.push(ball); return; } } }, beforeEnter(el){ //這個方法的執行是因為這是一個vue的監聽事件 let count = this.balls.length; while (count--) { let ball = this.balls[count]; if (ball.show) { let rect = ball.el.getBoundingClientRect(); //擷取小球的相對於視口的位移(小球高度) let x = rect.left - 32; let y = -(window.innerHeight - rect.top - 22); //負數,因為是從左上方往下的的方向 el.style.display = ‘‘; //清空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-hook類來單純被js操作 inner.style.webkitTransform = `translate3d(${x}px,0,0)`; inner.style.transform = `translate3d(${x}px,0,0)`; } } }, enter(el, done) { //這個方法的執行是因為這是一個vue的監聽事件 /* eslint-disable no-unused-vars */ let rf = el.offsetHeight; //觸發重繪html this.$nextTick(() => { //讓動畫效果非同步執行,提高效能 el.style.webkitTransform = ‘translate3d(0,0,0)‘; el.style.transform = ‘translate3d(0,0,0)‘; //處理內層動畫 let inner = el.getElementsByClassName(‘inner-hook‘)[0]; //使用inner-hook類來單純被js操作 inner.style.webkitTransform = ‘translate3d(0,0,0)‘; inner.style.transform = ‘translate3d(0,0,0)‘; el.addEventListener(‘transitionend‘, done); //Vue為了知道過渡的完成,必須設定相應的事件監聽器。 }); }, afterEnter(el) { //這個方法的執行是因為這是一個vue的監聽事件 let ball = this.dropBalls.shift(); //完成一次動畫就刪除一個dropBalls的小球 if (ball) { ball.show = false; el.style.display = ‘none‘; //隱藏小球 } } }
關於transitionend
關於drop方法,是實現每一個ball的show屬性和el屬性處理,並且點擊一次會自動將一個小球放到dropBalls數組裡面,放到裡面就代表的是一個小球已經被開始執行動畫,但是由於動畫是非同步,所以先主動設定.
關於getBoundingClientRect(位移的計算是從左上方開始)
使用getBoundingClientRect擷取到當前元素的座標,然後需要位移的left減去元素的寬擷取真正的最終位移x座標
使用getBoundingClientRect擷取到當前元素的座標,然後需要當前螢幕的高度減去元素的top再減去元素本身的高度擷取到真正的最終位移y座標,並且這個是負數,因為是從左上方往下的方向
關於html重繪
因為瀏覽器對於重繪是有要求並且是有隊列完成的,這是主要為了效能,雖然動畫隱藏了小球display none,但沒有觸發html重繪,或者說沒有立即觸發html重繪,所以需要手動
let rf = el.offsetHeight; 這是一個手動觸發html重繪的方法
網頁效能管理詳解 http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html
高效能JavaScript 重排與重繪http://www.cnblogs.com/zichi/p/4720000.html
.ball-container .ball position fixed left: 32px bottom: 22px z-index:200 transition: all .6s cubic-bezier(0.49, -0.29, 0.75, 0.41) .inner width 16px height 16px border-radius 50% background rgb(0,160,220) transition: all .6s linear
關於cubic-bezier(0.49, -0.29, 0.75, 0.41),是動畫拋物曲線(貝茲路徑)的配置,基於css3實現,http://cubic-bezier.com/#.17,.67,.83,.67,參考貝茲路徑與CSS3動畫、SVG和canvas的基情 ,至於拋物線放在外層就是為了控制內層的元素的軌道和方向的.
參考自1190000009294321
vue.js加入購物車小球動畫