1. 程式人生 > >8102 年,如何實現帶動畫的折疊面板

8102 年,如何實現帶動畫的折疊面板

事情 max 容易 為我 後來 pre gin 1.2 預覽效果

作為一個經常寫後端代碼的程序員,偶爾寫寫前端代碼也是勉強可以應付的。最近在重構某網站的時候,需要重新實現一個折疊面板。因為用了 Angular 這樣酷炫的前端框架,我相信,就算沒有 jQuery 這樣的工具,手擼一個折疊面板應該沒啥問題。就當我按照自己的直覺寫完第一版代碼之後,簡單的運行了一下,我就發現事情好像並沒有那麽簡單。

如果你願意動手嘗試的話,可以把下面的代碼復制到 這裏,在線預覽效果

// v1 in less
.panel-content {
    margin: .4rem 1.2rem;
    overflow: hidden;
    transition: height .5s;
    &.collapsed {
        height: 0;
    }
    &.expanded {
        height: auto;
    }
}

我通過 JavaScript 讓一個 div 的類在 collapsedexpanded 之間切換。折疊的時候設置元素高度為 0,展開的時候設置高度為 auto。這樣運行出來的效果就是,雖然面板在展開與折疊狀態之間切換了,但是並沒有出現我想要的動畫效果。經過一番檢索,我發現,即使已經 8102 年了,我們還是無法為 height: 0height:auto 設置 transition

經過爆棧網上大佬的指點,我們可以使用 max-height 來實現這樣的折疊效果:https://stackoverflow.com/a/8331169/6120806 。然後我就寫出了第二版 LESS:

// v2 in less
.panel-content {
  background:tan;
  margin-top: 10px;
  overflow: hidden;

  &.collapsed {
    transition: max-height 0.50s;
    max-height: 0;
  }

  &.expanded {
    max-height: 9999px;
    transition: max-height 0.50s;
  }
}

這裏有一個需要註意的地方,在展開狀態下,需要把 max-height 設置為一個較大的值,避免面板內部的元素因為溢出而被隱藏。這下,動畫效果就有了。

不過要是只有這麽一點坑是對不起這個標題的,如果你使用的是第二版的代碼,那麽你就會發現一個詭異的問題,當收起面板的時候,會產生明顯的延遲,跟那個答案中的演示效果出入很大,難道是因為他用的是 :hover 觸發動畫而我使用切換 class 觸發動畫這點不同嗎?

再次經過一番檢索,在爆棧網發現了對應的解決方案:https://stackoverflow.com/a/39103740/6120806。如果要通過切換 class 實現動畫,我們需要顯式的為收起的動畫指定一個時間函數 cubic-bezier(0, 1, 0, 1)

,於是便有了下面的第三版。

.panel-content {
  background:tan;
  margin-top: 10px;
  overflow: hidden;

  &.collapsed {
    transition: max-height 0.50s cubic-bezier(0, 1, 0, 1);
    max-height: 0;
  }

  &.expanded {
    max-height: 999px;
    transition: max-height 0.50s cubic-bezier(1, 0, 1, 0);
  }
}

這下已經接近完美了,展開與收起的動畫都十分流暢,沒有任何延遲。不過,我看著這個動畫突然感覺有些不對勁,為什麽收起的時候動畫的速度會感覺比較慢而展開的時候速度那麽快?後來仔細閱讀了上面提到的 Issue 下面的討論,找到了答案:因為我們把展開狀態下的 max-height 設置的太大了,所以 transition 中設置的動畫時間並不是我們觀察到的動畫時間。為了應對這個問題,我們需要稍微延長一下展開的動畫時間。

雖然已經 8102 年了,但是自己實現一個折疊面板,確實不太容易啊。

8102 年,如何實現帶動畫的折疊面板