监控鼠标滚动动画
需求
之前在工作中遇到的需求。色塊里面放了具體內(nèi)容,有文字或文字加圖片。要求并排的3個色塊在鼠標往下滾動的過程中慢慢從下往上浮現(xiàn),當(dāng)滾動到一定距離后,色塊內(nèi)容更改,新的并排色塊重新從下往上浮現(xiàn),脫離動效后如果屏幕向上滾動,色塊以相反效果展示。具體效果如下GIF所示,黑色部分是頁面外的調(diào)試界面。
問題分析
上面的需求已經(jīng)做了一層分析,將UI的想法抽象出來,用程序員的語言描述一遍,但這層分析還遠遠還不夠。
DOM結(jié)構(gòu)設(shè)計
難點在于整個動效DOM的結(jié)構(gòu)設(shè)計。
首先我們需要理解,頁面在向下滾動的過程中,高度會不斷增大,我們?nèi)庋劭吹絼有]有下移,但實際上動效在父結(jié)點中一直在往下掉。我們不僅要考慮并排色塊,同時要考慮上面的紫色和粉色色塊,因為在向下滾動過程中,它們是靜止不動的,并沒有按照正常的邏輯往下滾,所以它們的靜止本身也是一種動效。所以當(dāng)鼠標往下滾動時,我們需要考慮兩種動效,一種是并排色塊逐漸浮現(xiàn)消失的動效,另一種是紫色色塊和粉色色塊(下面合二為一改稱靜止色塊)的靜止動效。
在動效外,需要再包一層div作為動效的父元素,動效在這個父元素里面滾動。舉個例子,就像一個滑梯,有個小女孩在上面往下滑,我們的視角(屏幕窗口)只定格在孩子以及周圍一小塊環(huán)境身上,我們能感受到孩子在往下滑,但是看不到完整的滑梯。
說到動效,我們自然而然會想到定位屬性position,通過上面的分析,一開始我嘗試的是絕對定位和固定定位。鼠標往下滾動時,監(jiān)控屏幕高度,當(dāng)滾動到一定的高度時,用固定定位將靜止色塊固定在屏幕的一個位置,計算高度,不斷修改并排色塊的css參數(shù),其中包含絕對定位(通過不斷刷新這些參數(shù)達到浮現(xiàn)效果,在下面會詳細說明)。可惜這個方案不夠完美,具體表現(xiàn)在,當(dāng)我們滾動時,在將靜止色塊的定位屬性值從默認變成fixed的那一刻,整個元素會卡一下,而并排色塊由于不斷刷新絕對定位且屏幕同時往下滾動,會出現(xiàn)明顯的抖動。總之,這種方案的表現(xiàn)非常不流暢,影響觀感,不信的朋友大可嘗試一番。
嘗試使用粘性定位
既然使用粘性定位,那么以什么內(nèi)容作為對象呢?在上面列舉的小女孩滑滑梯的例子中,我們可以想到,對象應(yīng)該就是小女孩。小女孩即是兩種動效的結(jié)合,因為我們的視角跟隨著小女孩,所以在我們的視角中,有些元素即是自然而然靜止的。我們可以將例子繼續(xù)生動一些,假如小女孩在下滑的過程中,不斷向我們招手,其他身體部位則保持不動。那么手臂即可看做并排色塊,其他部位看做靜止色塊。此刻思路逐漸清晰了,dom結(jié)構(gòu)設(shè)計大概如下:
<div class="滑梯"><div class="小女孩"><div class="粉色色塊"></div><div class="紫色色塊"></div><div class="并排色塊">...</div></div> </div>我們的視角在小女孩身上,所以應(yīng)該對小女孩使用粘性布局:
.小女孩 {height: 100vh; // 整個元素高度占滿一個屏幕position: sticky; // 粘性定位top: 0; // 整屏黏在頂部,不會展示小女孩以外的內(nèi)容,直到滾出滑梯... }滑梯要足夠長:
.滑梯 {height: 300vh; // 設(shè)計長度為3屏高 }至此,從原理分析了整個動效DOM的設(shè)計,我認為這一層相對重要也更難一些。
并排色塊動效詳細設(shè)計
我們繼續(xù)引用上述小女孩滑滑梯的例子。
具體思路:監(jiān)聽屏幕滾動高度,當(dāng)高度到達滑梯頂部時,動效開始(接下來說的動效僅指并排色塊動效),計算小女孩與滑梯頂部的距離,分別更改并排色塊與父元素的頂內(nèi)邊距(padding-top)以及色塊的透明度(opacity)。另外,因為色塊在中途會更換,所以其實是有6個不同的色塊,分成2組,均勻變化。需要再添加一個控制參數(shù),控制每組色塊的顯隱,當(dāng)高度達到某一點時,一組色塊立即隱藏,換另一組色塊逐漸浮現(xiàn)。
所以并排色塊內(nèi)部DOM結(jié)構(gòu)應(yīng)該如下:
<div class="并排色塊"><div class="第1組"><div class="色塊1"></div><div class="色塊2"></div><div class="色塊3"></div></div><div class="第二組"><div class="色塊4"></div><div class="色塊5"></div><div class="色塊6"></div></div> </div>通過以上分析,我們需要監(jiān)控高度差,實時更新2個參數(shù):opacity、padding-top以及整組元素的顯隱狀態(tài),這里需要使用JS函數(shù)實現(xiàn),具體實現(xiàn)看代碼,值得一提的是,并排色塊向上提升的快慢,透明度變化的速率,都可以自己調(diào)節(jié)。比如增加一個額外的參數(shù)作為變化速率,實時更改透明度時加上這個速率。
我的設(shè)計是滑梯占3屏高,原始狀態(tài)占一屏高,第一組色塊動效變化占一屏高,第二組色塊動效占一屏高。
具體實現(xiàn)
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>一種滾動動效</title><style>.head {width: 100%;height: 400px;background-color: aqua;}.footer {width: 100%;height: 1000px;background-color: brown;}.body {width: 100%;height: 300vh;}.body-full-screen {height: 100vh;padding-top: 100px;position: sticky;top: 0;text-align: center;}.body-content {text-align: center;}.body-title {width: 800px;height: 100px;background-color: pink;margin: 0 auto;margin-bottom: 60px;}.body-des {width: 1200px;height: 200px;background-color: purple;margin: 0 auto;margin-bottom: 80px;}.body-num-first,.body-num-second {display: flex;justify-content: space-between;width: 1500px;margin: 0 auto;padding-top: 120px;}.body-num-item {width: 200px;height: 200px;}.body-num-1 {background-color: red;}.body-num-2 {background-color: green;}.body-num-3 {background-color: blue;}.body-num-4 {background-color: salmon;}.body-num-5 {background-color: khaki;}.body-num-6 {background-color: peru;}.hide {display: none;}.opacity-zero {opacity: 0;}</style> </head><body><div><div class="head"></div><div class="body"><div class="body-full-screen"><div class="body-title"></div><div class="body-des"></div><div class="body-num-first opacity-zero"><div class="body-num-1 body-num-item"></div><div class="body-num-2 body-num-item"></div><div class="body-num-3 body-num-item"></div></div><div class="body-num-second opacity-zero hide"><div class="body-num-4 body-num-item"></div><div class="body-num-5 body-num-item"></div><div class="body-num-6 body-num-item"></div></div></div></div><div class="footer"></div></div><script src="https://code.jquery.com/jquery-3.3.1.min.js"integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script><script>let screenHeight = $(window).height()let bodyTop = $('.body').offset().top$(window).scroll(function () {let currentTop = $(window).scrollTop()if (currentTop > bodyTop && currentTop < (bodyTop + screenHeight)) {$('.body-num-first').css('display', 'flex')$('.body-num-second').css('display', 'none')let firstOpacityValue = (currentTop - bodyTop) / screenHeightlet firstPaddingTopValue = (1 - firstOpacityValue) * 120 + 'px'$('.body-num-first').css({'opacity': firstOpacityValue,'padding-top': firstPaddingTopValue})} else if (currentTop >= (bodyTop + screenHeight) && currentTop < (bodyTop + 2 * screenHeight)) {$('.body-num-first').css('display', 'none')$('.body-num-second').css('display', 'flex')let secondOpacityValue = (currentTop - bodyTop - screenHeight) / screenHeightlet secondPaddingTopValue = (1 - secondOpacityValue) * 120 + 'px'$('.body-num-second').css({'opacity': secondOpacityValue,'padding-top': secondPaddingTopValue})}})</script> </body></html>總結(jié)
- 上一篇: 【论文笔记 2】CNN经典入门STRIV
- 下一篇: Android Rom修改