摘要:動畫庫學(xué)習(xí)筆記可以很方便的用做下拉刷新,抽獎轉(zhuǎn)盤等效果,我一直很好奇他是如何工作的,尤其是它能完美模擬原生的平滑滾動和慣性回彈等效果,而且體積小,速度快。當(dāng)軸逐漸增加到達(dá)時,當(dāng)前值軸會到達(dá)目標(biāo)值。類似的還有,屬性值的排序會造成影響。
AlloyTouch動畫庫學(xué)習(xí)筆記
alloyTouch可以很方便的用做下拉刷新,抽獎轉(zhuǎn)盤等效果,我一直很好奇他是如何工作的,尤其是它能完美模擬原生的平滑滾動和慣性回彈等效果,而且體積小,速度快。
閱讀代碼前,我的思考拖拽的慣性效果實(shí)現(xiàn),看上去這種效果的原理很簡單,但是真正實(shí)踐的時候還是有疑問:
怎么檢測到松開鼠標(biāo)那一刻的速度(初速)呢?
假設(shè)我拖拽的中途突然停止,再松開,要怎么處理?
拖拽力度很大的情況如何處理?
如果慣性滾動的移動的距離超出邊界,回彈效果怎么做?
拖拽超出邊界的橡皮筋效果怎么做?
源代碼閱讀帶著這些疑問,我開始了代碼閱讀之旅,下面的筆記沒有完完全全的講解整個框架,只是挑了我覺得(辣雞如我)容易疑惑的地方。
初始化this.isTouchStart = false;
這個變量是為了判斷用戶是否是從目標(biāo)DOM觸摸開始,有可能是先在wrapper觸摸,再移動至目標(biāo)DOM,如果是這種情況,不觸發(fā)滾動。
bind(this.element, "touchstart", this._start.bind(this)); bind(this.eventTarget, "touchend", this._end.bind(this)); bind(this.eventTarget, "touchcancel", this._cancel.bind(this));
接下來重點(diǎn)就在于這3個函數(shù)了,初始化綁定DOM的事件。
touchstart對應(yīng)AlloyTouch.prototype._start。
_start: function (evt) { this.isTouchStart = true; this.touchStart.call(this, evt, this.target[this.property]); cancelAnimationFrame(this.tickID); this._calculateIndex(); this.startTime = new Date().getTime(); //起始時間 this.x1 = this.preX = evt.touches[0].pageX; this.y1 = this.preY = evt.touches[0].pageY; this.start = this.vertical ? this.preY : this.preX; //startPoint this._firstTouchMove = true; //這里才是判斷是否初次觸摸 this._preventMove = false; },touchmove
對應(yīng)AlloyTouch.prototype._move。
這里有段代碼一直讓我疑惑很久,為什么touchstart和touchmove間隔大于300ms時,startTime和start(startPoint)要重新設(shè)置呢?
按我的理解,為了方便檢測速度,當(dāng)此次touchmove事件觸發(fā)時間比startTime大于300ms時,重新設(shè)定計算速度的startPoint,這樣可以在拖拽軌跡中截取合理的起止長度和時間間隔,計算初速,一般拖拽過程有以下3中情況:
假設(shè)拖拽的時長小于300ms,startPoint則用touchstart時設(shè)置的,
假設(shè)拖拽時長大于300ms,startPoint用滿足條件的新touchmove點(diǎn)。
拖拽中途停止,不產(chǎn)生慣性效果(一般情況下,鼠標(biāo)停止的時間會大于300ms)
這里我有個疑問,為什么不直接用最后一個touchmove點(diǎn)作為startPoint呢?
我的理解是,最后觸發(fā)的touchmove事件和touchend事件間隔時間很短,雖然間隔時間(dt)可以取得的精度很高,但是,移動的距離差(dv)的單位是px,假設(shè)物體移動了1.999px,最后瀏覽器還是按1px計算,在dt很小的的情況下,誤差就變大了。
對于問題5:橡皮筋效果的實(shí)現(xiàn):拖拽時,如果超出邊界,則增加移動的阻力,即用outerFactor。
touchend對應(yīng)AlloyTouch.prototype._end。
var dt = new Date().getTime() - this.startTime; if (dt < 300) {...}
對于問題4:判斷時間間隔是否小于300ms,如果大于,則判定是拖著不動,再松開,此時沒有慣性效果。
對于問題3:慣性滾動的距離destination超出邊界max且大于最大值maxRegion(默認(rèn)600px)時,則慣性滾動的最大距離為max + springMaxRegion(默認(rèn)60px),如下圖。
_to的實(shí)現(xiàn)alloyTouch內(nèi)部所有的動畫執(zhí)行都交給_to完成,類似$.fn.animate,實(shí)現(xiàn)如下
/** * 執(zhí)行過度效果 * @param value 目標(biāo)值 * @param time 過渡時間 * @param ease 緩動函數(shù) * @param onChange * @param onEnd * @private */ _to: function (value, time, ease, onChange, onEnd) { if (this.fixed) return; var el = this.target, property = this.property; var current = el[property]; var dv = value - current; var beginTime = new Date(); var self = this; var toTick = function () { var dt = new Date() - beginTime; if (dt >= time) { el[property] = value; onChange && onChange.call(self, value); onEnd && onEnd.call(self, value); return; } el[property] = dv * ease(dt / time) + current; el[property] = a; self.tickID = requestAnimationFrame(toTick); //cancelAnimationFrame必須在 tickID = requestAnimationFrame(toTick);的后面 onChange && onChange.call(self, el[property]); }; toTick(); },
我們替換一下原有的ease函數(shù),也可以達(dá)到同樣效果,這里我使用TweenJS提供的緩動函數(shù)
let a = Tween.Quad.easeOut(dt, current, dv, time); // console.log(a); // el[property] = dv * ease(dt / time) + current; el[property] = a; self.tickID = requestAnimationFrame(toTick); //cancelAnimationFrame必須在 tickID = requestAnimationFrame(toTick);的后面 onChange && onChange.call(self, el[property]);總結(jié) 初速計算
alloyTouch的大體思路就是在一段拖拽軌跡上,以touchend作為endPoint,再向前300ms內(nèi)選取一個startPoint,由兩點(diǎn)計算出初速。
緩動函數(shù)相關(guān)知識var Tween = { Quad: { /** * * @param t 時間(x軸) * @param b 初始值 * @param c 改變的大小 * @param d 持續(xù)時間 * @return {*} */ easeOut: function(t,b,c,d){ return -c *(t/=d)*(t-2) + b; } } }
x軸是時間,y軸是當(dāng)前值,b是y軸的初始值,x軸的初始值是0,t是當(dāng)前時間。當(dāng)t(x軸)逐漸增加到達(dá)d時,當(dāng)前值(y軸)會到達(dá)目標(biāo)值(b+c)。
查看展示
擴(kuò)展使用alloyTouch可以很方便的做出類似IOS的select效果
做3D效果就更方便啦
要注意的問題CSS3中transform:rotateX(30px) translateZ(50px)和transform: translateZ(50px) rotateX(30px)的效果是不一樣的!!!
前者是先旋轉(zhuǎn)(此時Z軸的方向已經(jīng)發(fā)生改變),再往Z軸偏移50px,后者是先往Z軸偏移50px,并以當(dāng)前為點(diǎn)基準(zhǔn),再旋轉(zhuǎn)。類似的還有perspective,屬性值的排序會造成影響。
對此,我提了一個issue,大家有興趣可以去看看
參考文獻(xiàn)
JavaScript Tween算法及緩動效果
緩動函數(shù)速查表
alloyTouch
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/88074.html
摘要:不論實(shí)在應(yīng)用游戲操作系統(tǒng)等許多層面,監(jiān)聽用戶觸摸,給用戶真實(shí)的運(yùn)動反饋是很常見的應(yīng)用場景。正是為了解決這類問題而生。版本不支持該事件運(yùn)動結(jié)束比如上面是運(yùn)動的屬性,必須要擁有屬性才能正常工作。 傳送門 Github地址:https://github.com/AlloyTeam/... 簡介 AlloyTouch的本質(zhì)是運(yùn)動一個數(shù)字,把數(shù)字的物理變化映射到你想映射的任何屬性上。所以帶來了廣...
摘要:同行這么做使用實(shí)現(xiàn)圓形進(jìn)度條前端掘金在開發(fā)微信小程序的時候,遇到圓形進(jìn)度條的需求。實(shí)現(xiàn)也談數(shù)組去重前端掘金的數(shù)組去重是一個老生常談的話題了。百度前端技術(shù)學(xué)院自定義前端掘金一標(biāo)簽概念元素表示用戶界面中項目的標(biāo)題。 閑話圖片上傳 - 掘金作者:孫輝,美團(tuán)金融前端團(tuán)隊成員。15年畢業(yè)加入美團(tuán),相信技術(shù),更相信技術(shù)只是大千世界里知識的一種,個人博客: https://sunyuhui.com ...
摘要:同行這么做使用實(shí)現(xiàn)圓形進(jìn)度條前端掘金在開發(fā)微信小程序的時候,遇到圓形進(jìn)度條的需求。實(shí)現(xiàn)也談數(shù)組去重前端掘金的數(shù)組去重是一個老生常談的話題了。百度前端技術(shù)學(xué)院自定義前端掘金一標(biāo)簽概念元素表示用戶界面中項目的標(biāo)題。 閑話圖片上傳 - 掘金作者:孫輝,美團(tuán)金融前端團(tuán)隊成員。15年畢業(yè)加入美團(tuán),相信技術(shù),更相信技術(shù)只是大千世界里知識的一種,個人博客: https://sunyuhui.com ...
摘要:是整個圖片在屏幕上的區(qū)域,圖片顯示區(qū)域會根據(jù)的不同而所不同,通過的方式,計算出最終顯示區(qū)域。到達(dá)邊界滾動上下一個圖片有了之前縮放拖拽的基礎(chǔ),這部分就比較簡單了。 GestureConfig 參數(shù)說明參數(shù)描述默認(rèn)值minScale縮放最小值0.8animationMinScale縮放動畫最小值,當(dāng)縮放結(jié)束時回到m...
閱讀 2628·2021-11-19 09:56
閱讀 874·2021-09-24 10:25
閱讀 1632·2021-09-09 09:34
閱讀 2195·2021-09-09 09:33
閱讀 1052·2019-08-30 15:54
閱讀 541·2019-08-29 18:33
閱讀 1264·2019-08-29 17:19
閱讀 505·2019-08-29 14:19