精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

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

開發 前端
FLIP 是四個單詞的首字母,First、Last、Invert、Play,這四個單詞給我們提供了完成動畫的具體思路。First 表示元素初始時的具體信息,在 html 環境中,這個事情是比較容易就能做到的,我們可以利用 getBoundingClientRect? 或者 getComputedStyle 來拿到元素的初始信息。

有一種能夠快速實現復雜動畫交互的動畫思維 FLIP,為了介紹這個動畫思維,我準備了三個案例

一、FLIP

FLIP 是四個單詞的首字母,First、Last、Invert、Play,這四個單詞給我們提供了完成動畫的具體思路。

First 表示元素初始時的具體信息,在 html 環境中,這個事情是比較容易就能做到的,我們可以利用 getBoundingClientRect 或者 getComputedStyle 來拿到元素的初始信息。

Last 表示元素結束時的位置信息。此時我們可以直接改變元素的位置,把元素放到新的節點上去。這樣我們就可以直接使用同樣的方式拿到結束時的元素具體信息。

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

Play 表示動畫開始執行。在代碼上通常 Invert 表示傳參,Play 表示具體的動畫執行。

接下來我們使用三個案例來進一步學習這個動畫思想。

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

案例效果如圖所示。

案例的 html 結構如下:

<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 對象。

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

First,記錄元素初始位置信息。此時我們把開始的 X 位置信息保存在子節點對象上,我們也可以單獨另起一個數組來保存所有子節點的具體信息。

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

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

當然也可以單獨在這一步把屬性位置信息保存起來。

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 表示動畫的執行。

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 瀏覽器已經支持。

該動畫接口使用起來也比較簡單,跟 keyframes 類似。

animate(keyframes, options)

keyframes 表示關鍵幀數組,options 表示動畫持續時間,或者包含多個時間屬性,用于配置動畫函數或者 iterations、delay 等常見屬性,與 css 的動畫屬性基本保持一致。

你也可以自己封裝一個類似的方法,或者使用成熟的第三方工具庫,能達到類似效果的方式也比較多。

然后在點擊按鈕時,執行即可。

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

三、案例二:多屬性變化

案例效果展示如圖:

元素多屬性動畫并不會增加多少實現復雜度,只是多記錄幾個元素而已。這個案例包含了 x/y/backgroundColor 三個屬性。

First,記錄初始信息。

// 記錄開始位置信息
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,直接改變元素節點位置。

因為改變節點位置之后,能夠輕易獲取到元素新的位置的具體屬性,所以這一步可以稱之為 Last。

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。

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})
  })
}

最后,點擊執行。

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

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

上面那兩個案例,在實踐中基本上沒什么用,主要用于輔助學習。因此大家可能對于高級感和優雅感的體會不是那么深刻。

第三個案例則以在實踐中,在前端很少有項目能夠做到的共享元素動畫,來為大家介紹這種動畫思想方案的厲害之處。

共享元素動畫在前端是一個很少被提及的概念,但是在客戶端的開發中,卻已經運用非常廣泛。

對于前端而言,這代表了未來頁面交互的主要發展方向。例如在小紅書的 web 端已經實現了該功能。

在 FLIP 的指導思想下,該功能實現起來也并不復雜。

First,記錄元素的初始信息。

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。

Last,點擊元素之后,出現彈窗。此時我們把相關的兩個節點插入到正確的位置上即可。

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

  modal.id = 'modal'
  modal.appendChild(current)
  document.body.appendChild(modal)
}

Invert and Play. 也是比較簡單,就是獲取新節點的位置,然后設置動畫即可。

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})
}

最后給每個元素添加點擊事件。

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

彈窗上也需要新增一個點擊事件,用于執行彈窗消失的動畫。

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()
  }
}

并在運動結束之后,刪除彈窗節點。

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

一個共享元素動畫,就這么簡單的實現了。

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

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

也就是說,我們只需要把這里的兩個點擊事件,結合路由事件和參數傳遞,就能做到跟小紅書一樣的共享元素路由轉場效果。

不過至于如何封裝讓代碼更加簡潔,本文就不再擴展啦,交給大家自己思考。

責任編輯:姜華 來源: 這波能反殺
相關推薦

2024-05-09 08:20:29

AC架構數據庫冗余存儲

2025-05-23 10:20:00

2020-03-04 17:03:10

數據分析思維說明

2022-02-25 14:42:09

OpenHarmon環境搭建鴻蒙

2010-03-26 13:34:47

CentOS安裝

2022-06-06 15:44:24

大數據數據分析思維模式

2020-12-16 10:12:52

大數據小數據人工智能

2022-03-01 09:58:10

高并發架構開發

2011-02-25 13:52:18

Proftpd管理

2011-02-25 13:52:18

Proftpd管理

2016-12-23 21:11:05

深度學習思維方式大數據

2021-10-26 16:49:34

系統性能定位

2011-07-04 10:17:38

JDBC

2017-08-24 15:02:01

前端增量式更新

2022-06-22 09:44:41

Python文件代碼

2022-07-07 10:33:27

Python姿勢代碼

2020-12-23 10:10:23

Pythonweb代碼

2020-12-09 10:15:34

Pythonweb代碼

2011-04-06 10:09:56

MySQL數據庫安裝

2010-05-27 11:04:32

點贊
收藏

51CTO技術棧公眾號

图片一区二区| 成人免费网址| 日本女人一区二区三区| 久久国产精品电影| 婷婷五月精品中文字幕| 丝袜美腿诱惑一区二区三区| 国产精品久久久久久久久免费樱桃| 成人在线播放av| 日韩欧美不卡视频| 999精品色在线播放| 亚洲国产女人aaa毛片在线| 天堂社区在线视频| 超碰在线97国产| 亚洲国产岛国毛片在线| 国产欧美日韩一区二区三区| 中文字幕视频二区| 亚洲激情精品| 欧美成人一区在线| 免费看日本黄色片| 开心激情综合| 欧美一区二区成人6969| 国产天堂在线播放| 国产极品人妖在线观看| 中文字幕制服丝袜成人av | 四虎影视精品| 日韩三级免费观看| 一起操在线视频| 97久久香蕉国产线看观看| 亚洲综合无码一区二区| 亚洲精品电影在线一区| 欧美精品少妇| 不卡电影一区二区三区| 91亚洲精品在线| 超碰在线免费97| 鲁大师成人一区二区三区| 午夜精品久久久久久久白皮肤| 看黄色录像一级片| 成人精品天堂一区二区三区| 国产视频精品va久久久久久| 国产精品一区二区人妻喷水| 亚洲视频三区| 欧美大片拔萝卜| 夜夜爽久久精品91| 色狠狠一区二区三区| 日本丶国产丶欧美色综合| av动漫在线看| 中文字幕在线直播| 五月综合激情日本mⅴ| 免费不卡av在线| av毛片午夜不卡高**水| 午夜精品福利视频网站| 精品无码一区二区三区在线| 国产资源在线观看入口av| 五月激情综合网| 日韩a∨精品日韩在线观看| av今日在线| 欧美体内谢she精2性欧美| 日本少妇高潮喷水视频| 成人香蕉视频| 日本黄色一区二区| 波多野结衣天堂| 欧美黄页免费| 欧美一区二区在线播放| 人妻巨大乳一二三区| 一区二区三区免费在线看| 日韩精品最新网址| av黄色一级片| 香蕉精品久久| 色偷偷亚洲男人天堂| 日本裸体美女视频| 国产精品porn| 欧美性在线观看| 成人免费一区二区三区| 国产在线国偷精品产拍免费yy| 91gao视频| 天堂а在线中文在线无限看推荐| 久久美女高清视频| 亚洲无玛一区| 日韩123区| 色综合久久久久网| 国产精品嫩草影院8vv8| 国产极品模特精品一二| 亚洲剧情一区二区| 欧美性x x x| 9色精品在线| 国产欧美精品xxxx另类| www久久久com| 国产亚洲一区字幕| 一本色道久久88亚洲精品综合| 操人在线观看| 欧美视频中文一区二区三区在线观看| 在线a免费观看| 欧美一区自拍| 久久综合网hezyo| 日韩男人的天堂| 久久精品国产99久久6| 国产成人精品日本亚洲11| 蜜桃视频在线观看网站| 亚洲精品一卡二卡| 欧美精品一区免费| 精品国产乱码一区二区三区| 亚洲天堂视频在线观看| 久久国产精品波多野结衣| 奇米影视一区二区三区| 国产偷久久久精品专区| 国产黄a三级三级三级av在线看| 亚洲成人av在线电影| 九色porny自拍| 欧美一级二级三级视频| 欧美精品在线观看| 在线观看免费视频a| 91视视频在线观看入口直接观看www| 一本久道久久综合| 澳门成人av网| 欧美精品一区二区三区蜜桃| 2014亚洲天堂| 日本一不卡视频| 免费影院在线观看一区| 青春草视频在线| 3atv在线一区二区三区| 五月婷六月丁香| 久久先锋影音| 久久久久久久免费| 丁香花电影在线观看完整版| 欧美丰满少妇xxxbbb| 亚洲精品国产精品国自| 免费久久99精品国产自在现线| 国产高清在线精品一区二区三区| 蜜桃视频网站在线| 欧美视频一区二区三区在线观看| 中日韩精品一区二区三区| 影音先锋久久精品| 91传媒视频在线观看| av观看在线| 91精品国产免费| 中文字幕在线观看2018| 九九在线精品视频| 中文精品视频一区二区在线观看| 电影一区二区| 中文字幕日韩高清| 一级aaaa毛片| 国产精品电影院| 超碰在线公开97| 日韩精品二区| 国产综合视频在线观看| 欧美成人视屏| 欧美高清视频在线高清观看mv色露露十八| 91免费在线看片| 久久国产精品区| www.黄色网址.com| 亚洲成人影音| 国模私拍一区二区三区| 俄罗斯嫩小性bbwbbw| 亚洲成人动漫av| 国产三级视频网站| 天堂成人国产精品一区| 亚洲欧洲久久| 高清一区二区中文字幕| 欧美高清自拍一区| 狠狠综合久久av一区二区 | 无码人妻丰满熟妇精品| 久久综合一区二区| 国产视频1区2区3区| 欧美/亚洲一区| 国产福利久久| 激情开心成人网| 日韩有码在线电影| 久久精品欧美一区二区三区不卡| 欧美大片一区二区| 久久久久久久99| 久久精子c满五个校花| 在线观看日本一区二区| 欧美~级网站不卡| 精品国产一区二区三区四区精华 | 欧美一级高清免费| 成人午夜在线观看视频| 在线电影欧美成精品| 久久香蕉精品视频| 久久亚洲欧美国产精品乐播| 亚洲第一狼人区| 欧美区一区二| 奇米精品在线| 日韩一区免费| 欧美最猛性xxxx| 日本激情视频在线观看| 亚洲а∨天堂久久精品喷水| 国产黄色免费视频| 亚洲精品日日夜夜| a级一a一级在线观看| 蜜桃久久精品一区二区| 欧美中日韩在线| 欧美日韩水蜜桃| 99中文视频在线| 亚洲播播91| 欧美激情在线一区| 98在线视频| 亚洲精品电影在线观看| 亚洲图片小说视频| 色域天天综合网| 成人免费精品动漫网站| 久久久久亚洲蜜桃| 91精品啪在线观看国产| 另类综合日韩欧美亚洲| 国产97在线 | 亚洲| 综合久久精品| 亚洲精品欧洲精品| 婷婷亚洲精品| 国产精品一区二区你懂得| 久久夜夜久久| 国产精品成人v| 免费看男女www网站入口在线| 不卡伊人av在线播放| 国产一级网站视频在线| 日韩精品欧美激情| 国产91久久久| 欧美一区二区日韩| 国产精品久久久国产盗摄| 91九色最新地址| 亚洲欧美综合另类| 天天综合天天综合色| 精品无码m3u8在线观看| 亚洲色图视频免费播放| av最新在线观看| 亚洲国产精华液网站w| 一级片视频免费看| 久久影院午夜片一区| 毛茸茸free性熟hd| 成人精品鲁一区一区二区| 黄色片子免费看| 国产美女精品在线| 亚洲欧美日本一区二区三区| 六月丁香综合在线视频| 国产精品区在线| 免费观看在线综合| 手机版av在线| 理论片日本一区| 中文字幕第88页| 麻豆国产精品777777在线| 天天综合网日韩| 久久国内精品自在自线400部| 日本999视频| 美女视频黄免费的久久| 亚洲精品午夜在线观看| 麻豆精品在线观看| 最新免费av网址| 国内一区二区视频| 亚洲天堂av一区二区三区| 狠狠狠色丁香婷婷综合激情| 永久免费黄色片| 国产寡妇亲子伦一区二区| 美女露出粉嫩尿囗让男人桶| 成人高清视频免费观看| 麻豆国产精品一区| 久久久91精品国产一区二区精品| www.黄色在线| 亚洲啪啪综合av一区二区三区| 日本黄色免费片| 一区二区三区免费在线观看| 国产性70yerg老太| 欧美性猛交xxxx乱大交3| 日韩国产亚洲欧美| 在线综合+亚洲+欧美中文字幕| 99热在线只有精品| 日韩av影院在线观看| 麻豆app在线观看| 日韩网站在线观看| 日本一级理论片在线大全| 91国产精品视频在线| 日韩av大片站长工具| 国产在线高清精品| 北条麻妃在线一区二区免费播放| 久久久久久99| 久久一区二区三区喷水| 91免费国产精品| 丝袜美腿亚洲一区二区图片| 亚洲美女性囗交| a在线播放不卡| 国产又粗又硬视频| 亚洲成年人网站在线观看| 无码人妻丰满熟妇精品 | 无码精品一区二区三区在线| 亚洲一级黄色av| 欧美巨大xxxx做受沙滩| 国产精品成人品| 超碰一区二区三区| 亚洲一区二区高清视频| 在线免费观看欧美| 国产九九热视频| 成人黄色777网| av在线播放中文字幕| 亚洲va国产天堂va久久en| 久久久999久久久| 亚洲成色777777在线观看影院| 在线观看国产原创自拍视频| 欧美精品福利视频| 羞羞视频在线观看一区二区| 久久亚裔精品欧美| 国产精品豆花视频| 永久免费的av网站| 久久综合久久综合九色| 免费在线一区二区三区| 欧美视频在线一区二区三区| 五月婷婷狠狠干| 欧美精品在线极品| 久久久加勒比| 欧美精品v日韩精品v国产精品| 午夜视频一区| 国产成人在线综合| 久久久99免费| 欧美三级午夜理伦| 精品久久久久久久久久久久包黑料| 91九色在线porn| 日本一区二区在线免费播放| h视频久久久| 中文字幕の友人北条麻妃| 看片网站欧美日韩| 国产91丝袜美女在线播放| 日韩欧美精品中文字幕| 欧美一级淫片aaaaaa| 九九热这里只有精品6| 亚洲黑人在线| 一区二区三区免费看| 日韩经典中文字幕一区| 强伦人妻一区二区三区| 欧美日韩一区二区三区在线免费观看| 精品人妻av一区二区三区| 精品国产一区av| 四虎国产精品成人免费影视| 天天久久人人| 麻豆精品在线观看| 免费91在线观看| 欧美美女直播网站| 麻豆网站视频在线观看| 国产主播欧美精品| 91综合久久| 中文字幕一区久久| 亚洲欧美中日韩| 99热精品在线播放| 欧美激情18p| 成人看片爽爽爽| 精品久久一二三| 久久免费精品国产久精品久久久久| 黑人精品无码一区二区三区AV| 日韩精品视频在线观看网址| 欧美亚洲日本精品| 日本免费高清一区二区| 免费高清在线一区| 最新一区二区三区| 日韩一级黄色片| jizz一区二区三区| 鲁丝一区二区三区免费| 日韩vs国产vs欧美| 丝袜美腿小色网| 亚洲成人aaa| 亚洲电影观看| 亚洲看片网站| 国产一级精品在线| 偷偷操不一样的久久| 亚洲热线99精品视频| 成人在线中文| 精品国产一区二区三区无码| 91蜜桃在线免费视频| 特级西西444www大胆免费看| 久久亚洲国产精品| 精品成人自拍视频| 韩国一区二区av| 亚洲美女精品一区| 噜噜噜久久,亚洲精品国产品| 欧美一级大片在线观看| 波多野结衣一区| ass极品水嫩小美女ass| 一本一本久久a久久精品综合麻豆| 国产黄在线观看免费观看不卡| 91精品久久久久久久久久入口 | 97在线看福利| 日韩一区三区| 日本不卡视频一区| 日本高清不卡在线观看| 午夜av在线免费观看 | 久久中文视频| 成人免费看片载| 欧美性色黄大片| 免费在线看污片| 天堂资源在线亚洲视频| 成人午夜av电影| 在线视频1卡二卡三卡| 久久久久久综合网天天| 青青草国产成人a∨下载安卓| 精品人妻人人做人人爽夜夜爽| 色哟哟国产精品免费观看| a级片国产精品自在拍在线播放| 免费久久一级欧美特大黄| 国产精品亚洲一区二区三区在线| 波多野结衣国产| 欧美日韩国产成人| 日本一区二区在线看| 久久久国产精品无码| 欧美福利视频导航| 欧美精品资源| 鲁一鲁一鲁一鲁一澡|