日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

练习动画最好的方式(二):屏幕指纹开锁动画效果

發布時間:2024/3/13 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 练习动画最好的方式(二):屏幕指纹开锁动画效果 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這部分時間比較忙,正是我所在行業中的旺季,也沒有時間更新,這篇文章我會用SCSS+GSAP實現一個屏幕指紋的登錄效果,讓我們先來看看效果圖

開始創作

第一步:將指紋繪制轉為SVG,

我用 Adob??e Illustrator 用鋼筆工具追蹤指紋,得到這組路徑:

<svg width='180' height='320'><path d="M46.1,214.3c0,0-4.7-15.6,4.1-33.3"/> <path d="M53.5,176.8c0,0,18.2-30.3,57.5-13.7"/><path d="M115.8,166.5c0,0,19.1,8.7,19.6,38.4"/><path d="M47.3,221c0,0,3.1-2.1,4.1-4.6s-5.7-20.2,7-36.7c8.5-11,22.2-19,37.9-15.3"/><path d="M102.2,165.4c10.2,2.7,19.5,10.4,23.5,20.2c6.2,15.2,4.9,27.1,4.1,39.4"/><path d="M51.1,226.5c3.3-2.7,5.1-6.3,5.7-10.5c0.5-4-0.3-7.7-0.3-11.7"/><path d="M129.3,200.1"/><path d="M56.3,197.9c3.1-16.8,17.6-29.9,35.1-28.8c17.7,1.1,30.9,14.9,32.8,32.2"/><path d="M124.2,207.9c0.5,9.3,0.5,18.7-2.1,27.7"/><path d="M54.2,231.1c2.1-2.6,4.6-5.1,6.3-8c4.2-6.8,0.9-14.8,1.5-22.3c0.5-7.1,3.4-16.3,10.4-19.7"/><path d="M77.9,178.2c9.3-5.1,22.9-4.7,30.5,3.3"/><path d="M113,186.5c0,0,13.6,18.9,1,54.8"/><path d="M57.3,235.2c0,0,5.7-3.8,9-12.3"/><path d="M111.7,231.5c0,0-4.1,11.5-5.7,13.6"/><path d="M61.8,239.4c9.3-8.4,12.7-19.7,11.8-31.9c-0.9-12.7,3.8-20.6,18.5-21.2"/><path d="M97.3,188.1c8.4,2.7,11,13,11.3,20.8c0.4,11.8-2.5,23.7-7.9,34.1c-0.1,0.1-0.1,0.2-0.2,0.3c-0.4,0.8-0.8,1.5-1.2,2.3c-0.5,0.8-1,1.7-1.5,2.5"/><path d="M66.2,242.5c0,0,15.3-11.1,13.6-34.9"/><path d="M78.7,202.5c1.5-4.6,3.8-9.4,8.9-10.6c13.5-3.2,15.7,13.3,14.6,22.1"/><path d="M102.2,219.7c0,0-1.7,15.6-10.5,28.4"/><path d="M72,244.9c0,0,8.8-9.9,9.9-15.7"/><path d="M84.5,223c0.3-2.6,0.5-5.2,0.7-7.8c0.1-2.1,0.2-4.6-0.1-6.8c-0.3-2.2-1.1-4.3-0.9-6.5c0.5-4.4,7.2-6.9,10.1-3.1c1.7,2.2,1.7,5.3,1.9,7.9c0.4,3.8,0.3,7.6,0,11.4c-1,10.8-5.4,21-11.5,29.9"/><path d="M90,201.2c0,0,4.6,28.1-11.4,45.2"/><path d="M67.3,219C65,188.1,78,180.1,92.7,180.3c18.3,2,23.7,18.3,20,46.7"/> </svg> 復制代碼

效果:

第二步:實現動畫

我將重點介紹這里的重要部分,你可以參考演示以獲取完整代碼。

填寫指紋: 讓我們創建手機屏幕和指紋的 HTML 結構。

<div class="demo"><div class="demo__screen demo__screen--clickable"><svg class="demo__fprint" viewBox="0 0 180 320"> <path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--pinkish" d="M46.1,214.3c0,0-4.7-15.6,4.1-33.3"/><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--purplish" d="M53.5,176.8c0,0,18.2-30.3,57.5-13.7"/><path class="demo__fprint-path demo__fprint-path--removes-forwards demo__fprint-path--pinkish" d="M115.8,166.5c0,0,19.1,8.7,19.6,38.4"/> </svg>

到目前為止,樣式非常簡單。請注意,我在整個演示中都使用了 Sass——并有助于我們完成一些更重的工作。

$scale: 1.65; $purplish-color: #8742cc; $pinkish-color: #a94a8c; $bg-color: #372546;.demo {background: linear-gradient(45deg, lighten($pinkish-color, 10%), lighten($purplish-color, 10%));min-height: 100vh;display: flex;justify-content: center;align-items: center;font-size: 0;user-select: none;overflow: hidden;position: relative;&__screen {position: relative;background-color: $bg-color;overflow: hidden;flex-shrink: 0;&--clickable {cursor: pointer;-webkit-tap-highlight-color: transparent;}}&__fprint-path {stroke-width: 2.5px;stroke-linecap: round;fill: none;stroke: white;visibility: hidden;transition: opacity 0.5s ease;&--pinkish {stroke: $pinkish-color;}&--purplish {stroke: $purplish-color;} }&__fprint {width: 180px * $scale;height: 320px * $scale;position: relative;top: 20px * $scale;overflow: visible;background-image: url('fprintBackground.svg');background-size: cover;&--no-bg {background-image: none;}} }

現在是困難的部分:使指紋具有交互性。這就是我將用來填充每個單獨路徑的方法。

創建一個描述路徑元素的類,以便以后更容易操作路徑。

class Path {constructor(selector, index) {this.index = index;this.querySelection = document.querySelectorAll(selector)[index];this.length = this.querySelection.getTotalLength();this.$ = $(selector).eq(index);this.setDasharray();this.removesForwards = this.$.hasClass('demo__fprint-path--removes-forwards');}setDasharray() {this.$.css('stroke-dasharray', `${this.length} ${this.length + 2}`);return this;}offset(ratio) {this.$.css('stroke-dashoffset', -this.length * ratio + 1);return this;}makeVisible() {this.$.css('visibility', 'visible');return this;} } 復制代碼

大體思路是這樣的:為我們指紋中的每條路徑創建一個此類的實例,并在每一幀中修改它們。路徑將以-1(完全不可見)的偏移比率開始,然后將每幀以恒定值增加偏移比率(我們將在此處稱為“偏移”),直到它們到達0(完全可見)。此時填充動畫將結束。

還要處理用戶停止點擊或按下鼠標按鈕的情況。在這種情況下,我們將在相反的方向上設置動畫(從每幀的偏移量中減去一個常數值,直到它-1再次到達)。

創建一個函數來計算每一幀的偏移增量——后面我們會用到的。

function getPropertyIncrement(startValue, endValue, transitionDuration) {//制作60 fps的動畫const TICK_TIME = 1000 / 60;const ticksToComplete = transitionDuration / TICK_TIME;return (endValue - startValue) / ticksToComplete; } 復制代碼

第三步:制作動畫

我們將指紋路徑保存在一個數組中:

let fprintPaths = [];// 為每個現有路徑創建一個 Path 實例。 // 首先把路徑設為不可見,等JavaScript 運行完成之后,我們將它設置為在 CSS 中不可見。 這樣我們就可以抵消它們,然后使它們可見。 for (let i = 0; i < $(fprintPathSelector).length; i++) {fprintPaths.push(new Path(fprintPathSelector, i));fprintPaths[i].offset(-1).makeVisible(); } 復制代碼

我們將為動畫中的每一幀遍歷該數組,對路徑進行動畫處理:

let fprintTick = getPropertyIncrement(0, 1, TIME_TO_FILL_FPRINT);function fprintFrame(timestamp) {// 如果時間少于 1000 / 65 毫秒,我從最后一幀開始繪制(因為有刷新率更高的屏幕在那里,我們要做到所有設備看起來都一樣)。 為什么這里使用的是65而不是60呢,因為在60 Hz 屏幕中可能會跳幀。if (timestamp - lastRafCallTimestamp >= 1000 / 65) {lastRafCallTimestamp = timestamp;curFprintPathsOffset += fprintTick * fprintProgressionDirection;offsetAllFprintPaths(curFprintPathsOffset);}// 如果動畫未結束,則安排下一幀if (curFprintPathsOffset >= -1 && curFprintPathsOffset <= 0) {isFprintAnimationInProgress = true;window.requestAnimationFrame(fprintFrame);}// 動畫結束之后。 我們可以安排下一個動畫步驟else if (curFprintPathsOffset > 0) {curFprintPathsOffset = 0;offsetAllFprintPaths(curFprintPathsOffset);isFprintAnimationInProgress = false;isFprintAnimationOver = true;// 刪除帶有灰色路徑的背景$fprint.addClass('demo__fprint--no-bg');// 安排下一個動畫步驟 - 將其中一個路徑轉換為字符串startElasticAnimation();// 安排指紋清除window.requestAnimationFrame(removeFprint);}// 當用戶松開點擊的那一刻指紋恢復原狀else if (curFprintPathsOffset < -1) {curFprintPathsOffset = -1;offsetAllFprintPaths(curFprintPathsOffset);isFprintAnimationInProgress = false;} } 復制代碼

我們將在演示中附加一些事件偵聽器:

$screen.on('mousedown touchstart', function() {fprintProgressionDirection = 1;// 如果動畫已經在進行中,我們不會安排下一幀,因為它已經在 `fprintFrame` 中安排了。 此外,如果動畫已經結束,我們顯然不會安排它。 這就是為什么我們對這些條件有兩個單獨的標志if (!isFprintAnimationInProgress && !isFprintAnimationOver)window.requestAnimationFrame(fprintFrame); })// 在 `mouseup` / `touchend` 上,我們翻轉動畫方向 $(document).on('mouseup touchend', function() {fprintProgressionDirection = -1;if (!isFprintAnimationInProgress && !isFprintAnimationOver)window.requestAnimationFrame(fprintFrame); }) 復制代碼

現在我們應該完成點擊的部分了!演示:

第四步:去除指紋

這部分與制作部分非常相似,只是我們必須考慮這樣一個事實,即一些路徑在一個方向上移除,而其余路徑在另一個方向上移除。這就是我們之前添加--removes-forwards修飾符的原因。

首先,我們將有兩個額外的數組:一個用于向前刪除的路徑,另一個用于向后刪除的路徑:

const fprintPathsFirstHalf = []; const fprintPathsSecondHalf = [];for (let i = 0; i < $(fprintPathSelector).length; i++) {// ...if (fprintPaths[i].removesForwards)fprintPathsSecondHalf.push(fprintPaths[i]);elsefprintPathsFirstHalf.push(fprintPaths[i]); } 復制代碼

我們將編寫一個函數,將它們向正確的方向偏移:

function offsetFprintPathsByHalves(ratio) { fprintPathsFirstHalf.forEach(path => path.offset(ratio));fprintPathsSecondHalf.forEach(path => path.offset(-ratio)); } 復制代碼

我們還需要一個繪制框架的函數:

function removeFprintFrame(timestamp) {// 如果我們的速度超過 65 fps,則可能丟幀if (timestamp - lastRafCallTimestamp >= 1000 / 65) {curFprintPathsOffset += fprintTick * fprintProgressionDirection;offsetFprintPathsByHalves(curFprintPathsOffset);lastRafCallTimestamp = timestamp;}// 如果動畫未結束,則安排下一幀if (curFprintPathsOffset >= -1)window.requestAnimationFrame(removeFprintFrame);else {// 由于浮點錯誤,最終偏移量可能略小于 -1,因此如果超過該值,我們將為其分配 -1 并再動畫一幀curFprintPathsOffset = -1;offsetAllFprintPaths(curFprintPathsOffset);} }function removeFprint() {fprintProgressionDirection = -1;window.requestAnimationFrame(removeFprintFrame); } 復制代碼

現在剩下的就是removeFprint在我們完成指紋填充后調用:

function fprintFrame(timestamp) {// ...else if (curFprintPathsOffset > 0) {// ...window.requestAnimationFrame(removeFprint);}// ... } 復制代碼

得到的效果是這樣的:

第五步:動畫路徑結束

可以看到,由于指紋幾乎被移除,因此其某些路徑比開始時更長。我將它們移動到不同的路徑中,在適當的時候開始動畫。我可以將它們合并到現有路徑中,但這會困難得多,而且在 60fps 下幾乎沒有區別。

<path class="demo__ending-path demo__ending-path--pinkish" d="M48.4,220c-5.8,4.2-6.9,11.5-7.6,18.1c-0.8,6.7-0.9,14.9-9.9,12.4c-9.1-2.5-14.7-5.4-19.9-13.4c-3.4-5.2-0.4-12.3,2.3-17.2c3.2-5.9,6.8-13,14.5-11.6c3.5,0.6,7.7,3.4,4.5,7.1"/> 復制代碼

基本樣式:

&__ending-path {fill: none;stroke-width: 2.5px;stroke-dasharray: 60 1000;stroke-dashoffset: 61;stroke-linecap: round;will-change: stroke-dashoffset, stroke-dasharray, opacity;transform: translateZ(0);transition: stroke-dashoffset 1s ease, stroke-dasharray 0.5s linear, opacity 0.75s ease;&--removed {stroke-dashoffset: -130;stroke-dasharray: 5 1000;}&--transparent {opacity: 0;}&--pinkish {stroke: $pinkish-color;}&--purplish {stroke: $purplish-color;} } 復制代碼

添加--removed修飾符以在適當的時候流入這些路徑:

function removeFprint() {$endingPaths.addClass('demo__ending-path--removed');setTimeout(() => {$endingPaths.addClass('demo__ending-path--transparent');}, TIME_TO_REMOVE_FPRINT * 0.9);// ... } 復制代碼

指紋效果完成:

最后一步:指紋變形

這里我們需要使用 GSAP 的morphSVG 插件

創建一條路徑和一條線,它們將成為我們字符串的關鍵幀:

<line id='demo__straight-path' x1="0" y1="151.3" x2="180" y2="151.3"/> <path class="demo__hidden-path" id='demo__arc-to-top' d="M0,148.4c62.3-13.5,122.3-13.5,180,0"/> 復制代碼

然后我們將使用 morphSVG 來轉換關鍵幀之間的路徑:

const $elasticPath = $('#demo__elastic-path');const ELASTIC_TRANSITION_TIME_TO_STRAIGHT = 250; const WOBBLE_TIME = 1000;function startElasticAnimation() {$elasticPath.css('stroke-dasharray', 'none');const elasticAnimationTimeline = new TimelineLite();elasticAnimationTimeline.to('#demo__elastic-path', ELASTIC_TRANSITION_TIME_TO_STRAIGHT / 1000, {delay: TIME_TO_REMOVE_FPRINT / 1000 * 0.7,morphSVG: '#demo__arc-to-top'}).to('#demo__elastic-path', WOBBLE_TIME / 1000, {morphSVG: '#demo__straight-path',ease: Elastic.easeOut.config(1, 0.3)}) } 復制代碼

fprintFrame一旦指紋被填充,我們將在內部調用這個函數:

function fprintFrame(timestamp) {// ...else if (curFprintPathsOffset > 0) {// ...startElasticAnimation();// ...}// ... } 復制代碼

最終效果完成:

完整代碼?HTML:

<!DOCTYPE html> <html lang="en" > <head><meta charset="UTF-8"><title>CodePen - css-t. part 4</title><meta name="viewport" content="width=device-width, minimum-scale=1.0"><link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css"><link rel="stylesheet" href="./style.css"></head> <body><div class="demo"><div class="demo__screen demo__screen--clickable"><svg class="demo__fprint" viewBox="0 0 180 320"><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--pinkish" d="M46.1,214.3c0,0-4.7-15.6,4.1-33.3"/><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--purplish" d="M53.5,176.8c0,0,18.2-30.3,57.5-13.7"/><path class="demo__fprint-path demo__fprint-path--removes-forwards demo__fprint-path--pinkish" d="M115.8,166.5c0,0,19.1,8.7,19.6,38.4"/><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--pinkish" d="M47.3,221c0,0,3.1-2.1,4.1-4.6s-5.7-20.2,7-36.7c8.5-11,22.2-19,37.9-15.3"/><path class="demo__fprint-path demo__fprint-path--removes-forwards demo__fprint-path--pinkish" d="M102.2,165.4c10.2,2.7,19.5,10.4,23.5,20.2c6.2,15.2,4.9,27.1,4.1,39.4"/><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--purplish" d="M51.1,226.5c3.3-2.7,5.1-6.3,5.7-10.5c0.5-4-0.3-7.7-0.3-11.7"/><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--purplish" d="M56.3,197.9c3.1-16.8,17.6-29.9,35.1-28.8c17.7,1.1,30.9,14.9,32.8,32.2"/><path class="demo__fprint-path demo__fprint-path--removes-forwards demo__fprint-path--purplish" d="M124.2,207.9c0.5,9.3,0.5,18.7-2.1,27.7"/><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--pinkish" d="M54.2,231.1c2.1-2.6,4.6-5.1,6.3-8c4.2-6.8,0.9-14.8,1.5-22.3c0.5-7.1,3.4-16.3,10.4-19.7"/><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--purplish" d="M77.9,178.2c9.3-5.1,22.9-4.7,30.5,3.3"/><path class="demo__fprint-path demo__fprint-path--removes-forwards demo__fprint-path--purplish" d="M113,186.5c0,0,13.6,18.9,1,54.8"/><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--pinkish" d="M57.3,235.2c0,0,5.7-3.8,9-12.3"/><path class="demo__fprint-path demo__fprint-path--removes-forwards demo__fprint-path--pinkish" d="M111.7,231.5c0,0-4.1,11.5-5.7,13.6"/><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--purplish" d="M61.8,239.4c9.3-8.4,12.7-19.7,11.8-31.9c-0.9-12.7,3.8-20.6,18.5-21.2"/><path class="demo__fprint-path demo__fprint-path--removes-forwards demo__fprint-path--pinkish" d="M97.3,188.1c8.4,2.7,11,13,11.3,20.8c0.4,11.8-2.5,23.7-7.9,34.1c-0.1,0.1-0.1,0.2-0.2,0.3c-0.4,0.8-0.8,1.5-1.2,2.3c-0.5,0.8-1,1.7-1.5,2.5"/><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--purplish" d="M66.2,242.5c0,0,15.3-11.1,13.6-34.9"/><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--pinkish" d="M78.7,202.5c1.5-4.6,3.8-9.4,8.9-10.6c13.5-3.2,15.7,13.3,14.6,22.1"/><path class="demo__fprint-path demo__fprint-path--removes-forwards demo__fprint-path--pinkish" d="M102.2,219.7c0,0-1.7,15.6-10.5,28.4"/><path class="demo__fprint-path demo__fprint-path--removes-backwards demo__fprint-path--pinkish" d="M72,244.9c0,0,8.8-9.9,9.9-15.7"/><path class="demo__fprint-path demo__fprint-path--removes-forwards demo__fprint-path--pinkish" d="M84.5,223c0.3-2.6,0.5-5.2,0.7-7.8c0.1-2.1,0.2-4.6-0.1-6.8c-0.3-2.2-1.1-4.3-0.9-6.5c0.5-4.4,7.2-6.9,10.1-3.1c1.7,2.2,1.7,5.3,1.9,7.9c0.4,3.8,0.3,7.6,0,11.4c-1,10.8-5.4,21-11.5,29.9"/><path class="demo__fprint-path demo__fprint-path--removes-forwards demo__fprint-path--purplish" d="M90,201.2c0,0,4.6,28.1-11.4,45.2"/><path class="demo__fprint-path demo__fprint-path--pinkish" id='demo__elastic-path' d="M67.3,219C65,188.1,78,180.1,92.7,180.3c18.3,2,23.7,18.3,20,46.7"/><line id='demo__straight-path' x1="0" y1="151.3" x2="180" y2="151.3"/><path class="demo__hidden-path" id='demo__arc-to-top' d="M0,148.4c62.3-13.5,122.3-13.5,180,0"/><path class="demo__ending-path demo__ending-path--pinkish"d="M48.4,220c-5.8,4.2-6.9,11.5-7.6,18.1c-0.8,6.7-0.9,14.9-9.9,12.4c-9.1-2.5-14.7-5.4-19.9-13.4c-3.4-5.2-0.4-12.3,2.3-17.2c3.2-5.9,6.8-13,14.5-11.6c3.5,0.6,7.7,3.4,4.5,7.1"/><path class="demo__ending-path demo__ending-path--pinkish"d="M57.3,235.2c-14.4,9.4-10.3,19.4-17.8,21.1c-5.5,1.3-8.4-7.8-13.8-4.2c-2.6,1.7-5.7,7.7-4.6,10.9c0.7,2,4.1,2,5.8,2.4c3,0.7,8.4,3,7.6,7.2c-0.6,3-5,5.3-2.4,8.7c1.8,2.2,4.7,1.1,6.9,0.3c11.7-4.3,14.5,0.8,16.5,0.9"/><path class="demo__ending-path demo__ending-path--purplish"d="M79,246c-1.8,2.4-4.9,2.9-7.6,3.2c-2.7,0.3-5.8-0.8-7.7,1.6c-2.9,3.3,0.7,8.2-1.2,12c-1.5,2.8-4.5,2.4-6.9,1.3c-10.1-4.7-33.2-17.5-38.1-2.5c-1.1,3.4-1.9,7.5-1.3,11c0.6,4,5.6,7.9,7.7,2.3c0.8-2.1,3.1-8.6-1-8.9"/><path class="demo__ending-path demo__ending-path--pinkish"d="M91.8,248c0,0-3.9,6.4-6.2,9.2c-3.8,4.5-7.9,8.9-11.2,13.8c-1.9,2.8-4.4,6.4-3.7,10c0.9,5.2,4.7,12.5,9.7,14.7c5.2,2.2,15.9-4.7,13.1-10.8c-1.4-3-6.3-7.9-10-7.2c-1,0.2-1.8,1-2,2"/><path class="demo__ending-path demo__ending-path--purplish"d="M114.8,239.4c-2.7,6.1-8.3,12.8-7.8,19.8c0.3,4.6,3.8,7.4,7.8,9.1c8.9,3.8,19.7,0.4,28.6-1.3c8.8-1.7,19.7-3.2,23.7,6.7c2.8,6.8,6.1,14.7,4.4,22.2"/><path class="demo__ending-path demo__ending-path--pinkish"d="M129.9,224.2c-0.4,7.5-3.1,18,0.7,25c2.8,5.1,14.3,6.3,19.5,7.4c3.7,0.7,8.7,2.2,12-0.5c6.7-5.4,11.1-13.7,14.1-21.6c3.1-8-4.4-12.8-11.1-14.5c-5-1.3-19.1-0.7-21-6.7c-0.9-2.8,1.8-5.9,3.4-7.9"/></svg> </div> </div> <!-- partial --><script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js'></script> <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script> <script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/MorphSVGPlugin.min.js?r=182'></script><script src="./script.js"></script></body> </html>復制代碼

CSS:

*, *:before, *:after {box-sizing: border-box;margin: 0;padding: 0; }.demo {background: linear-gradient(45deg, #bd69a3, #a16ad7);min-height: 100vh;display: flex;justify-content: center;align-items: center;font-size: 0;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;overflow: hidden;position: relative; } .demo__screen {position: relative;background-color: #372546;overflow: hidden;flex-shrink: 0; } .demo__screen--clickable {cursor: pointer;-webkit-tap-highlight-color: transparent; } .demo__fprint-path {stroke-width: 2.5px;stroke-linecap: round;fill: none;stroke: white;visibility: hidden;transition: opacity 0.5s ease;will-change: stroke-dashoffset, stroke-dasharray;transform: translateZ(0); } .demo__fprint-path--pinkish {stroke: #a94a8c; } .demo__fprint-path--purplish {stroke: #8742cc; } .demo__fprint-path#demo__elastic-path {will-change: opacity;opacity: 1; } .demo__hidden-path {display: none; } .demo__fprint {width: 297px;height: 528px;position: relative;top: 33px;overflow: visible;background-image: url("fprintBackground.svg");background-size: cover; } .demo__fprint--no-bg {background-image: none; } .demo__ending-path {fill: none;stroke-width: 2.5px;stroke-dasharray: 60 1000;stroke-dashoffset: 61;stroke-linecap: round;will-change: stroke-dashoffset, stroke-dasharray, opacity;transform: translateZ(0);transition: stroke-dashoffset 1s ease, stroke-dasharray 0.5s linear, opacity 0.75s ease; } .demo__ending-path--removed {stroke-dashoffset: -130;stroke-dasharray: 5 1000; } .demo__ending-path--transparent {opacity: 0; } .demo__ending-path--pinkish {stroke: #a94a8c; } .demo__ending-path--purplish {stroke: #8742cc; } 復制代碼

JS:

$(document).ready(function() {if (!window.requestAnimationFrame) {window.requestAnimationFrame = function(cb) {setTimeout(() => cb(new Date()), 1000 / 60);}}const TIME_TO_FILL_FPRINT = 700; //msconst TIME_TO_REMOVE_FPRINT = 250;const ELASTIC_TRANSITION_TIME_TO_STRAIGHT = 250;const WOBBLE_TIME = 1000;const fprintPathSelector = '.demo__fprint-path';const $fprintPaths = $('.demo__fprint-path');const $fprint = $('.demo__fprint');const $screen = $('.demo__screen');const $endingPaths = $('.demo__ending-path');const $elasticPath = $('#demo__elastic-path');let isFprintAnimationInProgress = false;let isFprintAnimationOver = false;let curFprintPathsOffset = -1;let fprintProgressionDirection = 1; let lastRafCallTimestamp = 0;let fprintTick = getPropertyIncrement(0, 1, TIME_TO_FILL_FPRINT);let fprintPaths = [];const fprintPathsFirstHalf = [];const fprintPathsSecondHalf = [];for (let i = 0; i < $(fprintPathSelector).length; i++) {fprintPaths.push(new Path(fprintPathSelector, i));fprintPaths[i].offset(-1).makeVisible();if (fprintPaths[i].removesForwards)fprintPathsSecondHalf.push(fprintPaths[i]);elsefprintPathsFirstHalf.push(fprintPaths[i]);}function fprintFrame(timestamp) {if (timestamp - lastRafCallTimestamp >= 1000 / 65) {lastRafCallTimestamp = timestamp;curFprintPathsOffset += fprintTick * fprintProgressionDirection;offsetAllFprintPaths(curFprintPathsOffset);}if (curFprintPathsOffset >= -1 && curFprintPathsOffset <= 0) {isFprintAnimationInProgress = true;window.requestAnimationFrame(fprintFrame);}else if (curFprintPathsOffset > 0) {curFprintPathsOffset = 0;offsetAllFprintPaths(curFprintPathsOffset);isFprintAnimationInProgress = false;isFprintAnimationOver = true;$fprint.addClass('demo__fprint--no-bg');startElasticAnimation();fprintTick = getPropertyIncrement(0, 1, TIME_TO_REMOVE_FPRINT);window.requestAnimationFrame(removeFprint);}else if (curFprintPathsOffset < -1) {curFprintPathsOffset = -1;offsetAllFprintPaths(curFprintPathsOffset);isFprintAnimationInProgress = false;}}function removeFprint() {$endingPaths.addClass('demo__ending-path--removed');setTimeout(() => {$endingPaths.addClass('demo__ending-path--transparent');}, TIME_TO_REMOVE_FPRINT * 0.9);fprintProgressionDirection = -1;window.requestAnimationFrame(removeFprintFrame);}function removeFprintFrame(timestamp) {if (timestamp - lastRafCallTimestamp >= 1000 / 65) {curFprintPathsOffset += fprintTick * fprintProgressionDirection;offsetFprintPathsByHalves(curFprintPathsOffset);lastRafCallTimestamp = timestamp;}if (curFprintPathsOffset >= -1)window.requestAnimationFrame(removeFprintFrame);else {curFprintPathsOffset = -1;offsetAllFprintPaths(curFprintPathsOffset);}}function startElasticAnimation() {$elasticPath.css('stroke-dasharray', 'none');const elasticAnimationTimeline = new TimelineLite();elasticAnimationTimeline.to('#demo__elastic-path', ELASTIC_TRANSITION_TIME_TO_STRAIGHT / 1000, {delay: TIME_TO_REMOVE_FPRINT / 1000 * 0.7,morphSVG: '#demo__arc-to-top'}) .to('#demo__elastic-path', WOBBLE_TIME / 1000, {morphSVG: '#demo__straight-path',ease: Elastic.easeOut.config(1, 0.3)})} function offsetAllFprintPaths(ratio) {fprintPaths.forEach(path => path.offset(ratio));}function offsetFprintPathsByHalves(ratio) { fprintPathsFirstHalf.forEach(path => path.offset(ratio));fprintPathsSecondHalf.forEach(path => path.offset(-ratio));}$screen.on('mousedown touchstart', function() {fprintProgressionDirection = 1;if (!isFprintAnimationInProgress && !isFprintAnimationOver)window.requestAnimationFrame(fprintFrame);})$(document).on('mouseup touchend', function() {fprintProgressionDirection = -1;if (!isFprintAnimationInProgress && !isFprintAnimationOver)window.requestAnimationFrame(fprintFrame);}); });function getPropertyIncrement(startValue, endValue, transitionDuration) {const TICK_TIME = 1000 / 60;const ticksToComplete = transitionDuration / TICK_TIME;return (endValue - startValue) / ticksToComplete; }class Path {constructor(selector, index) {this.index = index;this.querySelection = document.querySelectorAll(selector)[index];this.length = this.querySelection.getTotalLength();this.$ = $(selector).eq(index);this.setDasharray();this.removesForwards = this.$.hasClass('demo__fprint-path--removes-forwards');}setDasharray() {this.$.css('stroke-dasharray', `${this.length} ${this.length + 2}`);return this;}offset(ratio) {this.$.css('stroke-dashoffset', -this.length * ratio + 1);return this;}makeVisible() {this.$.css('visibility', 'visible');return this;} } 復制代碼

總結

以上是生活随笔為你收集整理的练习动画最好的方式(二):屏幕指纹开锁动画效果的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。