日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

FLIP,一種高端優雅但簡單易用的前端動畫思維

來源: 責編: 時間:2024-05-16 08:58:35 146觀看
導讀有一種能夠快速實現復雜動畫交互的動畫思維 FLIP,為了介紹這個動畫思維,我準備了三個案例。一、FLIPFLIP 是四個單詞的首字母,First、Last、Invert、Play,這四個單詞給我們提供了完成動畫的具體思路。First 表示元素初始

sG128資訊網——每日最新資訊28at.com

有一種能夠快速實現復雜動畫交互的動畫思維 FLIP,為了介紹這個動畫思維,我準備了三個案例sG128資訊網——每日最新資訊28at.com

一、FLIP

FLIP 是四個單詞的首字母,First、Last、Invert、Play,這四個單詞給我們提供了完成動畫的具體思路。sG128資訊網——每日最新資訊28at.com

First 表示元素初始時的具體信息,在 html 環境中,這個事情是比較容易就能做到的,我們可以利用 getBoundingClientRect 或者 getComputedStyle 來拿到元素的初始信息。sG128資訊網——每日最新資訊28at.com

Last 表示元素結束時的位置信息。此時我們可以直接改變元素的位置,把元素放到新的節點上去。這樣我們就可以直接使用同樣的方式拿到結束時的元素具體信息。sG128資訊網——每日最新資訊28at.com

Invert 表示倒置。雖然元素到了結束時的節點位置,但是視覺上我們并沒有看到,此時要設計讓元素動畫從 First 通過動畫的方式變換到 Last,剛好我們又記錄了動畫的開始和結束信息,因此我們可以利用自己熟悉的動畫方式來完成 Invert。sG128資訊網——每日最新資訊28at.com

Play 表示動畫開始執行。在代碼上通常 Invert 表示傳參,Play 表示具體的動畫執行。sG128資訊網——每日最新資訊28at.com

接下來我們使用三個案例來進一步學習這個動畫思想。sG128資訊網——每日最新資訊28at.com

二、案例一:元素 X 軸位置隨機變化

案例效果如圖所示。sG128資訊網——每日最新資訊28at.com

sG128資訊網——每日最新資訊28at.com

案例的 html 結構如下:sG128資訊網——每日最新資訊28at.com

<div id="container">  <div class="item">1</div>  <div class="item">2</div>  <div class="item">3</div>  <div class="item">4</div>  <div class="item">5</div></div><button id="sort">隨機排序</button>

先獲取兩個關鍵 DOM 對象。sG128資訊網——每日最新資訊28at.com

const container = document.getElementById('container')const sortBtn = document.getElementById('sort')

First,記錄元素初始位置信息。此時我們把開始的 X 位置信息保存在子節點對象上,我們也可以單獨另起一個數組來保存所有子節點的具體信息。sG128資訊網——每日最新資訊28at.com

// 記錄開始位置信息function record(container) {  const all = [...container.children]  all.forEach((item, i) => {    const rect = item.getBoundingClientRect()    item.startX = rect.left  })}

Last,直接改變元素的節點位置。因為改變之后,元素在新的節點上,那么我們這里就可以單獨快捷獲取元素改變之后的位置信息,所以可以封裝一個方法,只改變元素的節點位置信息,而在需要的時候獲取 Last 即可。sG128資訊網——每日最新資訊28at.com

當然也可以單獨在這一步把屬性位置信息保存起來。sG128資訊網——每日最新資訊28at.com

function change() {  const all = [...container.children]  const len = all.length  all.forEach((item, i) => {    const newIndex = Math.floor(Math.random() * len)    if (newIndex !== i) {      const nextDOM = item.nextElementSibling      container.insertBefore(item, all[newIndex])      container.insertBefore(all[newIndex], nextDOM)    }  })}

Invert 和 play 在代碼實現上往往會耦合在一起,Invert 表示參數傳入,play 表示動畫執行。因此我們可以最后再定義一個方法 play 表示動畫的執行。sG128資訊網——每日最新資訊28at.com

function play(container) {  const all = [...container.children]  const len = all.length  all.forEach((item, i) => {    const rect = item.getBoundingClientRect()    const currentX = rect.left    item.animate([      { transform: `translateX(${item.startX - currentX}px)` },      { transform: 'translateX(0px)' }    ], {duration: 600})  })}

這里我使用了一個 DOM 元素自帶的 animate 方法,來完成動畫的實現,該方法目前還是一個實驗性的 api,在 2022 年提出,目前最新版的 chrome 瀏覽器已經支持。sG128資訊網——每日最新資訊28at.com

該動畫接口使用起來也比較簡單,跟 keyframes 類似。sG128資訊網——每日最新資訊28at.com

animate(keyframes, options)

keyframes 表示關鍵幀數組,options 表示動畫持續時間,或者包含多個時間屬性,用于配置動畫函數或者 iterations、delay 等常見屬性,與 css 的動畫屬性基本保持一致。sG128資訊網——每日最新資訊28at.com

你也可以自己封裝一個類似的方法,或者使用成熟的第三方工具庫,能達到類似效果的方式也比較多。sG128資訊網——每日最新資訊28at.com

然后在點擊按鈕時,執行即可。sG128資訊網——每日最新資訊28at.com

sortBtn.onclick = () => {  record(container)  change()  play(container)}

三、案例二:多屬性變化

案例效果展示如圖:sG128資訊網——每日最新資訊28at.com

sG128資訊網——每日最新資訊28at.com

元素多屬性動畫并不會增加多少實現復雜度,只是多記錄幾個元素而已。這個案例包含了 x/y/backgroundColor 三個屬性。sG128資訊網——每日最新資訊28at.com

First,記錄初始信息。sG128資訊網——每日最新資訊28at.com

// 記錄開始位置信息function record(container) {  const all = [...container.children]  all.forEach((item, i) => {    const rect = item.getBoundingClientRect()    item.startX = rect.left    item.startY = rect.top    item.bgColor = getComputedStyle(item)['backgroundColor']  })}

Last,直接改變元素節點位置。sG128資訊網——每日最新資訊28at.com

因為改變節點位置之后,能夠輕易獲取到元素新的位置的具體屬性,所以這一步可以稱之為 Last。sG128資訊網——每日最新資訊28at.com

function change() {  const all = [...container.children]  const len = all.length  all.forEach((item, i) => {    const newIndex = Math.floor(Math.random() * len)    if (newIndex !== i) {      const nextDOM = item.nextElementSibling      container.insertBefore(item, all[newIndex])      container.insertBefore(all[newIndex], nextDOM)    }  })}

Invert and Play。sG128資訊網——每日最新資訊28at.com

function play(container) {  const all = [...container.children]  const len = all.length  all.forEach((item, i) => {    const rect = item.getBoundingClientRect()    const currentX = rect.left    const currentY = rect.top    const bgColor = getComputedStyle(item, false)["backgroundColor"]    item.animate([      { transform: `translate(${item.startX - currentX}px, ${item.startY - currentY}px)`, backgroundColor: item.bgColor },      { transform: 'translate(0px, 0px)', backgroundColor: bgColor }    ], {duration: 600})  })}

最后,點擊執行。sG128資訊網——每日最新資訊28at.com

sortBtn.onclick = () => {  record(container)  change()  play(container)}

四、案例三:共享元素動畫

上面那兩個案例,在實踐中基本上沒什么用,主要用于輔助學習。因此大家可能對于高級感和優雅感的體會不是那么深刻。sG128資訊網——每日最新資訊28at.com

第三個案例則以在實踐中,在前端很少有項目能夠做到的共享元素動畫,來為大家介紹這種動畫思想方案的厲害之處。sG128資訊網——每日最新資訊28at.com

sG128資訊網——每日最新資訊28at.com

共享元素動畫在前端是一個很少被提及的概念,但是在客戶端的開發中,卻已經運用非常廣泛。sG128資訊網——每日最新資訊28at.com

sG128資訊網——每日最新資訊28at.com

對于前端而言,這代表了未來頁面交互的主要發展方向。例如在小紅書的 web 端已經實現了該功能。sG128資訊網——每日最新資訊28at.com

在 FLIP 的指導思想下,該功能實現起來也并不復雜。sG128資訊網——每日最新資訊28at.com

First,記錄元素的初始信息。sG128資訊網——每日最新資訊28at.com

const all = [...list.children]// 記錄開始位置信息all.forEach((item, i) => {  const rect = item.getBoundingClientRect()  item.startX = rect.left  item.startY = rect.top  item.width = rect.width  item.height = rect.height})

當我們點擊元素時,此時有兩個元素位置信息在發生變化,一個是背景彈窗。他的變化比較簡單,就是透明度的變化,因此我們不用記錄他的信息。另外一個就是共享的元素 item,此時我們記錄了四個信息:startX、startY、width、height。sG128資訊網——每日最新資訊28at.com

Last,點擊元素之后,出現彈窗。此時我們把相關的兩個節點插入到正確的位置上即可。sG128資訊網——每日最新資訊28at.com

function change(element) {  current = element.cloneNode(true)  modal = document.createElement('div')  modal.id = 'modal'  modal.appendChild(current)  document.body.appendChild(modal)}

Invert and Play. 也是比較簡單,就是獲取新節點的位置,然后設置動畫即可。sG128資訊網——每日最新資訊28at.com

function play(preItem) {  modal.animate([    {backgroundColor: `rgba(0, 0, 0, 0)`},    {backgroundColor: `rgba(0, 0, 0, ${0.3})`}  ], {duration: 600})  const rect = current.getBoundingClientRect()  const currentX = rect.left  const currentY = rect.top  const width = rect.width  const height = rect.height  const x = preItem.startX - currentX - (width - preItem.width) / 2  const y = preItem.startY - currentY - (height - preItem.height) / 2  console.log(x, y)  current.animate([    {      transform: `translate(${x}px, ${y}px)`,      width: `${preItem.width}px`,      height: `${preItem.height}px`    },    {      transform: 'translate(0px, 0px)',      height: `${height}px`,      width: `${width}px`    }  ], {duration: 600})}

最后給每個元素添加點擊事件。sG128資訊網——每日最新資訊28at.com

all.forEach((item, i) => {  item.onclick = (event) => {    change(event.target)    play(event.target)  }})

彈窗上也需要新增一個點擊事件,用于執行彈窗消失的動畫。sG128資訊網——每日最新資訊28at.com

modal.onclick = () => {  const ani = modal.animate([    {backgroundColor: `rgba(0, 0, 0, ${0.3})`},    {backgroundColor: `rgba(0, 0, 0, 0)`}  ], {duration: 600})  const rect = current.getBoundingClientRect()  const currentX = rect.left  const currentY = rect.top  const width = rect.width  const height = rect.height  const x = element.startX - currentX - (width - element.width) / 2  const y = element.startY - currentY - 100  current.animate([    {      transform: 'translate(0px, 0px)',      height: `${height}px`,      width: `${width}px`    },    {      transform: `translate(${x}px, ${y}px)`,      width: `${element.width}px`,      height: `${element.height}px`    },  ], {duration: 600})  console.log(x, y)  ani.onfinish = () => {    modal.remove()  }}

并在運動結束之后,刪除彈窗節點。sG128資訊網——每日最新資訊28at.com

ani.onfinish = () => {  modal.remove()}

一個共享元素動畫,就這么簡單的實現了。sG128資訊網——每日最新資訊28at.com

五、共享元素動畫擴展思考

如果我們要結合路由切換轉場來實現共享元素動畫,其實實現原理也是一樣的,非常的簡單,我們只需要在路由切換時,把共享元素的初始位置信息記錄下來并作為參數傳遞給下一個頁面即可。sG128資訊網——每日最新資訊28at.com

也就是說,我們只需要把這里的兩個點擊事件,結合路由事件和參數傳遞,就能做到跟小紅書一樣的共享元素路由轉場效果。sG128資訊網——每日最新資訊28at.com

不過至于如何封裝讓代碼更加簡潔,本文就不再擴展啦,交給大家自己思考。sG128資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-88310-0.htmlFLIP,一種高端優雅但簡單易用的前端動畫思維

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 詳解 PyTypeObject,Python 類型對象的載體

下一篇: Android:excludeFromRecents屬性使用分析

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 景东| 昌乐县| 沙湾县| 通许县| 桃江县| 紫阳县| 富蕴县| 安仁县| 黄陵县| 抚州市| 嫩江县| 旬邑县| 轮台县| 晴隆县| 交口县| 永川市| 大田县| 抚顺县| 梁山县| 彝良县| 黄梅县| 易门县| 平阳县| 华安县| 汨罗市| 鄂托克前旗| 容城县| 周口市| 黎川县| 石棉县| 保康县| 英山县| 阳高县| 攀枝花市| 远安县| 桑植县| 于田县| 河池市| 保德县| 屏东市| 东阳市|