<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      不定高元素動畫實(shí)現(xiàn)方案(下)

      前情

      最近小程序接了一個需求,需要實(shí)現(xiàn)一個列表,列表可展開收起,展開收起需要有一個動畫效果,而列表個數(shù)不定且每項(xiàng)內(nèi)容高度也不固定,所以是一個不定高的收起展開效果,于是特意抽時間嘗試了一些動畫實(shí)現(xiàn)方案,特此記錄

      通過js+css變量來實(shí)現(xiàn)

      實(shí)現(xiàn)思路是js獲取要實(shí)現(xiàn)動畫元素的高度,再通過css變量把高度設(shè)置在元素上,當(dāng)hover的時候,把元素的高度設(shè)為css變量

      關(guān)鍵代碼如下:

      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width">
        <title>JS Bin</title>
      </head>
      <body>
        <div class="container">
          <div class="inner">
            <div class="header">header</div>
            <ul class="list" id="list" style="--height:0px">
              <li>scale111111111</li>
              <li>scale2222222222</li>
              <li>scale333333333</li>
              <li>scale444444444</li>
            </ul>
          </div>
        </div>
      </body>
      </html>
      
      *{
        margin: 0;
        padding: 0;
      }
      .container{
        width: 100%;
        overflow: hidden;
      }
      .header{
        width: 100%;
        height: 48px;
        background-color: #ccc;
        display: flex;
        align-items: center;
        justify-content: center;
      }
      .list{
        background-color: green;
        height: var(--height)
      }
      
      document.addEventListener('DOMContentLoaded', () => {
        var list = document.querySelector('#list')
        list.style.setProperty('--height', list.scrollHeight + 'px')
      })
      

      演示地址:https://jsbin.com/besufuyihe/edit?html,css,js,output

      20250920_200532

      注意:

      css動畫使用比js要簡單,同時性能上也會有優(yōu)勢,所以能用css實(shí)現(xiàn)的就盡量用css實(shí)現(xiàn),此方式兼容性棒,JS干預(yù)也不是特別多

      通過js+Flip動畫來實(shí)現(xiàn)

      FLIP是一種高性能動畫技術(shù),常用于實(shí)現(xiàn)復(fù)雜動畫,代表四個步驟:

      1. First(初始):記錄元素的初始狀態(tài)
      2. Last(最終):設(shè)置元素到最終狀態(tài)并記錄
      3. Invert(反轉(zhuǎn)):計(jì)算差異并將元素恢復(fù)到初始狀態(tài)
      4. Play(播放):應(yīng)用過渡效果并播放動畫

      代碼如下:

      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width">
        <title>JS Bin</title>
      </head>
      <body>
        <div class="container" id="container">
          <div class="inner">
            <div class="header">header</div>
            <ul class="list">
              <li>Flip111111111</li>
              <li>Flip2222222222</li>
              <li>Flip333333333</li>
              <li>Flip444444444</li>
            </ul>
          </div>
        </div>
      </body>
      </html>
      
      *{
         margin: 0;
         padding: 0;
      }
      .container{
        width: 100%;
        height: 48px;
        overflow: hidden;
      }
      .header{
        width: 100%;
        height: 48px;
        background-color: #ccc;
        display: flex;
        align-items: center;
        justify-content: center;
      }
      .list{
        background-color: green;
      }
      
      document.addEventListener('DOMContentLoaded', () => {
        // 獲取容器元素
        const containero = document.querySelector('#container')
        
        // 鼠標(biāo)進(jìn)入容器時的FLIP動畫實(shí)現(xiàn)
        containero.addEventListener('mouseenter', () => {
          // 第一步(F-First):記錄初始狀態(tài)(隱式的,初始高度為48px)
          
          // 第二步(L-Last):設(shè)置元素為最終狀態(tài),獲取自然高度
          containero.style.height = 'auto';
          const conh = containero.scrollHeight; // 獲取內(nèi)容實(shí)際高度
          
          // 第三步(I-Invert):將元素恢復(fù)到初始狀態(tài)
          containero.style.height = '48px';
          containero.offsetHeight; // 觸發(fā)重繪,確保樣式應(yīng)用
          
          // 第四步(P-Play):添加過渡效果并播放動畫到最終狀態(tài)
          containero.style.transition = 'height .4s';
          containero.style.height = conh + 'px';
        })
      
        // 鼠標(biāo)離開時恢復(fù)初始高度
        containero.addEventListener('mouseleave', () => {
          containero.style.height = '48px';
        })
      })
      

      演示地址:https://jsbin.com/barihazasi/edit?html,css,js,output

      20250920_203017

      注意:

      Flip用于實(shí)現(xiàn)一些復(fù)雜動畫是非常常見的方式,動畫還是使用css3的transition,還是遵守一個原則,能用css實(shí)現(xiàn)動畫的還是用css來做

      純js來實(shí)現(xiàn)

      早期js實(shí)現(xiàn)動畫都是使用setInterval/setTimeout來實(shí)現(xiàn)動畫效果的,現(xiàn)在如果要用js來實(shí)現(xiàn)動畫可以使用requestAnimationFrame來代替,來看一下他們的對比

      1. 觸發(fā)時機(jī)與刷新頻率

      • setTimeout/setInterval
        • 按照指定的時間間隔(毫秒)觸發(fā)回調(diào)函數(shù)
        • 時間間隔是近似值,實(shí)際執(zhí)行會受 JavaScript 線程繁忙程度影響
        • 即使頁面處于后臺或隱藏狀態(tài),仍可能繼續(xù)執(zhí)行
        • 刷新頻率固定,無法與顯示器刷新率同步
      • requestAnimationFrame
        • 由瀏覽器決定執(zhí)行時機(jī),通常與顯示器刷新率同步(60Hz 屏幕約每 16ms 執(zhí)行一次)
        • 自動調(diào)整執(zhí)行頻率以匹配設(shè)備性能
        • 當(dāng)頁面處于后臺或標(biāo)簽頁隱藏時,會暫停執(zhí)行以節(jié)省資源
        • 執(zhí)行時機(jī)在瀏覽器重繪之前,確保動畫平滑

      2. 性能表現(xiàn)

      • setTimeout/setInterval
        • 可能導(dǎo)致動畫卡頓或跳幀,因?yàn)闊o法與瀏覽器渲染周期對齊
        • 多個定時器同時運(yùn)行時可能導(dǎo)致性能問題
        • 高頻率定時器 (如 10ms) 可能導(dǎo)致瀏覽器過度渲染,消耗不必要的資源
      • requestAnimationFrame
        • 瀏覽器會優(yōu)化動畫執(zhí)行,確保流暢性
        • 自動調(diào)整幀率,在性能不足時降低頻率
        • 不會在頁面不可見時執(zhí)行,節(jié)省 CPU/GPU 資源

      關(guān)鍵代碼如下:

      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width">
        <title>JS Bin</title>
      </head>
      <body>
        <div class="container" id="container">
          <div class="inner">
            <div class="header">header</div>
            <ul class="list">
              <li>js111111111</li>
              <li>js2222222222</li>
              <li>js333333333</li>
              <li>js444444444</li>
            </ul>
          </div>
        </div>
      </body>
      </html>
      
      *{
        margin: 0;
        padding: 0;
      }
      .container{
        width: 100%;
        height: 48px;
        overflow: hidden;
      }
      .header{
        width: 100%;
        height: 48px;
        background-color: #ccc;
        display: flex;
        align-items: center;
        justify-content: center;
      }
      .list{
        background-color: green;
      }
      
      document.addEventListener('DOMContentLoaded', () => {
        const containero = document.querySelector('#container')
        // 初始高度為48px(與CSS中定義的一致)
        const initH = 48;
        // 獲取容器完全展開時的高度
        const conh = containero.scrollHeight;
        // 每一幀增加/減少的高度像素
        const step = 5;
        // 標(biāo)記動畫是否正在運(yùn)行,防止多次觸發(fā)
        let isAnimating = false;
        
        containero.addEventListener('mouseenter', () => {
          // 如果已經(jīng)在動畫中,則不重新開始
          if (isAnimating) return;
          
          // 獲取當(dāng)前高度作為起點(diǎn)
          let currentHeight = parseInt(containero.offsetHeight);
          isAnimating = true;
          
          const expand = function () {
            // 增加高度
            currentHeight += step;
            
            // 檢查是否達(dá)到目標(biāo)高度
            if (currentHeight >= conh) {
              containero.style.height = conh + 'px';
              isAnimating = false;
              return;
            }
            
            // 設(shè)置新高度并繼續(xù)動畫
            containero.style.height = currentHeight + 'px';
            requestAnimationFrame(expand);
          }
          
          // 開始展開動畫
          requestAnimationFrame(expand);
        })
      
        // 鼠標(biāo)離開時恢復(fù)初始高度
        containero.addEventListener('mouseleave', () => {
          // 如果已經(jīng)在動畫中,則不重新開始
          if (isAnimating) return;
          
          // 獲取當(dāng)前高度作為起點(diǎn)
          let currentHeight = parseInt(containero.offsetHeight);
          isAnimating = true;
          
          const collapse = function () {
            // 減少高度
            currentHeight -= step;
            
            // 檢查是否達(dá)到初始高度
            if (currentHeight <= initH) {
              containero.style.height = initH + 'px';
              isAnimating = false;
              return;
            }
            
            // 設(shè)置新高度并繼續(xù)動畫
            containero.style.height = currentHeight + 'px';
            requestAnimationFrame(collapse);
          }
          
          // 開始收起動畫
          requestAnimationFrame(collapse);
        })
      })
      

      演示地址:https://jsbin.com/kunuqomale/edit?html,css,js,output

      20250920_210140

      注意:

      早期想實(shí)現(xiàn)動畫都是依賴js來做的,看這代碼量就知道用JS實(shí)現(xiàn)既復(fù)雜又性能一般,現(xiàn)在css3動畫已經(jīng)兼容性非常好了,推薦用css3動畫來實(shí)現(xiàn),使用js來實(shí)現(xiàn)動畫是最終選擇了,當(dāng)然真正項(xiàng)目開發(fā)也不會自己去寫js動畫函數(shù)了,市面上有很多強(qiáng)大易用的動畫庫,早期jQuery就自帶動畫函數(shù),還有我覺得市面上最強(qiáng)大的動畫庫GSAP是目前js實(shí)現(xiàn)動畫的首選了

      總結(jié)

      對于做技術(shù)的我們,每天都是提出問題解決問題的一個過程,過程中會嘗試各種方案,因?yàn)榻鉀Q問題的方案千千萬,每種方案都有自己的適合場景,此篇文章記錄了實(shí)現(xiàn)不定高內(nèi)容過渡效果的另外三種實(shí)現(xiàn)方式,上中下篇文章一共介紹了9種實(shí)現(xiàn)動畫的方式

      個人知識有限,如果你有更好的實(shí)現(xiàn)方案,希望不吝分享,一起學(xué)習(xí)一起進(jìn)步

      posted @ 2025-09-23 13:04  !win !  閱讀(128)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 成人午夜福利精品一区二区| 国产乱码精品一区二区上| 久久精品国产亚洲av成人| 一级做a爰片在线播放| 99中文字幕精品国产| av无码精品一区二区乱子| 人人人澡人人肉久久精品| 亚洲最大av资源站无码av网址| 少妇精品视频一码二码三| 九九热在线观看视频免费| 99久久激情国产精品| 视频一区视频二区视频三| 国产精品黄大片在线播放| 九九热免费精品视频在线| 精品无码成人片一区二区| 午夜男女爽爽影院在线| 国产精品日韩中文字幕| 国产精品亚洲а∨天堂2021| 久久婷婷五月综合色丁香花| 国产不卡av一区二区| 亚洲精品国产精品国自产| 精品自拍偷拍一区二区三区| 丰满少妇内射一区| 无码熟妇αⅴ人妻又粗又大| 色先锋av影音先锋在线| 亚洲VA成无码人在线观看天堂| 久爱www人成免费网站| 97精品人妻系列无码人妻| 国内揄拍国内精品人妻| 97午夜理论电影影院| 欧美日韩中文字幕久久伊人| 国产精品美女AV免费观看| 中文字幕国产精品日韩| 亚洲av中文一区二区| 激情国产一区二区三区四区| 人人妻人人做人人爽| 国产精品成人一区二区三区| 国产日韩精品一区在线不卡| 久久综合色一综合色88欧美| 无码专区 人妻系列 在线| 日本无遮挡吸乳视频|