一行代碼實現display"過渡動畫"原理

寫本文的原由

  • 上篇文章,提到如何讓display出現過渡動畫,卻沒有仔細介紹原理。
  • 爲了更好的讓想學習的人深刻理解因而加班加點寫下了這篇「短文」,我想之後仍是以短文爲主,否則你們看起來太累

正式開始

  • 初始化界面
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
          #app {
            width: 200px;
            height: 200px;
            background-color: red;
            display: none;
            transition: all 1s;
        }
    </style>
</head>

<body>
    <div id="app">
    </div>
    <button id="test">測試</button>
</body>

</html>

  • 此時我將app的display初始化爲none,而且寫入腳本文件
<style>
        #app {
            width: 200px;
            height: 200px;
            background-color: red;
            display: none;
        }
    </style>
    。。。
<script>
     test.onclick = function () {
        const app = document.querySelector('#app')
        console.log(app, 'app')
        app.style.transform = "translateX(200px)"
        app.style.display = "block"
    }
</script>
  • 初始化界面變成了這樣:

  • 此時,我點擊測試按鈕

  • 並無出現動畫,很是生硬的出來了,有一些場景我又要性能,好比初始化不渲染,可是當它出現又要有動畫的時候,就有可能使用這行代碼
test.onclick = function () {
        const app = document.querySelector('#app')
        console.log(app, 'app')
        app.style.display = "block"
        const height = app.offsetHeight
        app.style.transform = "translateX(200px)"
    }
  • 當我加入const height = app.offsetHeight這行代碼的時候,再點擊測試按鈕,display切換就順帶出來了「動畫」,有了過分效果
  • 爲何會出現動畫了呢? 由於我讀取dom的這些特殊屬性時,瀏覽器就會強制清空渲染隊列一次,讓我拿到最新的值。也就是說讀取的時候,其實已是display爲"block"了,所以。咱們出現了過渡動畫

效果以下所示:
image.pnghtml


出現「過渡動畫」是什麼狀況?

  • 其實display是不能出現動畫的,因此標題+了引號
  • 怎麼纔能有過渡?前端

    • 有數字的變化,例如透明度,從0-1.
    • 初始化有渲染展現的
    • transition裏面包含的屬性
    • ...等 你們能夠補充

爲何加了一行代碼後,就能出現動畫了?

  • 你們在寫現代前端框架,遇到最多的問題就是渲染的時期不肯定的問題。vue

    • 例如vue裏面的nextTick實現,有一個優雅降級的實現。它在mounted生命週期函數裏面去獲取dom節點時候,常常獲取不到或者獲取不到完整渲染的dom節點。(我好久沒有使用vue了,有問題能夠補充),爲何?
    • 像如今數據驅動的框架,只要數據改變了,對應邏輯綁定了數據的dom節點按道理應該更新,但是更新時機是咱們沒法肯定的,由於這中間有中間層,好比存在diff算法計算過程,可能存在隊列,由於當你頻繁修改數據的時候,框架自己要作優化,合併一段時間的數據更新再去真正更新dom,等這些事情都作完了,才能去更新dom節點,而後咱們才能看到最新數據對應的節點
    • 當咱們真的要去更新dom節點的時候,也存在一個隊列。這個就是瀏覽器的渲染隊列

---git

  • 若是你沒法理解我上面說的,能夠看我以前手寫React系列文章中的setState異步隊列實現

瀏覽器的渲染隊列

  • 何時最能體現這個隊列的做用?github

    • 頻繁直接操做dom時候,例如for循環裏面頻繁操做dom,這個時候瀏覽器就會優化咱們的操做,合併一部分操做一次性執行
    • 渲染隊列跟display的關聯
<script>
    test.onclick = function () {
        const app = document.querySelector('#app')
        console.log(app, 'app')
        app.style.display = "block"
        const height = app.offsetHeight
        app.style.transform = "translateX(200px)"
    }
</script>
  • 當咱們執行了app.style.display = "block"這行代碼時候,dom節點此時並無更新,js解析引擎是聰明的,它發現你後面立刻有代碼要修改dom節點,會先存入隊列中集中一次性操做
  • 當咱們執行了app.offsetHeight這行代碼時候,發現咱們須要讀取dom節點的屬性,瀏覽器懼怕如今隊列中沒有執行的操做會讓你讀取到不正確的值引起BUG,因而就會清空渲染隊列而且執行,讓你拿到最精確/新的

  • 當你請求向瀏覽器請求一些 style信息的時候,就會讓瀏覽器flush隊列,好比:算法

    • offsetTop, offsetLeft, offsetWidth, offsetHeight
    • scrollTop/Left/Width/Height
    • clientTop/Left/Width/Height
    • width,height
  • 當你請求上面的一些屬性的時候,瀏覽器爲了給你最精確的值,須要flush隊列,
  • 由於隊列中可能會有影響到這些值的操做。即便你獲取元素的佈局和樣式信息跟最近發生或改變的佈局信息無關,
  • 瀏覽器都會強行刷新渲染隊列。

清空渲染隊列後

  • 當讀取offsetHeight屬性後,咱們清空了渲染隊列,那麼此時dom從新渲染完成後,此時display已是block了。並且展現在界面上面了,咱們再操做dom屬性就會出現過渡動畫了。

最後

  • 紙上得來終覺淺,多實踐、多思考是走向更高級別必經之路,想要看我以前手寫源碼文章的,個人gitHub源碼地址是:https://github.com/JinJieTan/Peter-,記得Star

  • 歡迎你關注個人公衆號:[前端巔峯] 若是感受對你有幫助,能夠點個/在看,讓更多人看到個人這篇文章
相關文章
相關標籤/搜索