網站搜尋

javascript - 在 CSS3 中重新啟動動畫:有比移除元素更好的方法嗎?


我有一個需要在點擊時重新啟動的 CSS3 動畫。它是一個顯示剩餘時間的條。我正在使用 scaleY(0) 轉換來製作這個效果。

現在我需要通過將條形恢復到 scaleY(1) 來重新啟動動畫,然後再讓它變回 scaleY(0)。我第一次嘗試設置 scaleY(1) 失敗了,因為它需要相同的 15 秒才能恢復到全長。即使我將持續時間改為 0.1 秒,我也需要延遲或鏈接 scaleY(0) 的賦值,以讓條形補充完成。對於這麼簡單的任務,這感覺太複雜了。

我還發現了一個有趣的小技巧,可以通過將元素從文檔中移除,然後重新插入它的克隆來重新啟動動畫:http://css-tricks.com/restart-css-animation/

它有效,但有沒有更好的方式來重新啟動 CSS 動畫?我正在使用 Prototype 和 Move.js,但我並不限於使用它們。

答案#1

不需要使用 timeout,使用 reflow 來應用更改:

function reset_animation() {
  var el = document.getElementById('animated');
  el.style.animation = 'none';
  el.offsetHeight; /* trigger reflow */
  el.style.animation = null; 
}
#animated {
  position: absolute;
  top: 70px;
  width: 50px; height: 50px;
  background-color: black;
  animation: bounce 3s ease-in-out infinite;
}
@keyframes bounce {
  0% { left: 0; }
  50% { left: calc( 100% - 50px ); }
  100% { left: 0; }
}
<div id="animated"></div>
<button onclick="reset_animation()">Reset</button>

答案#2

只需透過 JavaScript 設定 animation 屬性為 "none",然後設定一個 timeout 將該屬性改回 "",這樣它就會再次繼承自 CSS。

這裡是 Webkit 的示範:http://jsfiddle.net/leaverou/xK6sa/ 但是,請記住,在現實使用中,你也應該至少包含 -moz-。

答案#3

@ZachB 關於 Web Animation API 的回答看起來像是做這件事的「正確」™方式,但不幸的是似乎需要你透過 JavaScript 來定義你的動畫。不過它吸引了我的注意,我找到了一些相關的、有用的東西:

Element.getAnimations() 和 Document.getAnimations()

到 2021 年為止,他們的支援相當不錯。

就我而言,我想同時重新啟動頁面上的所有動畫,所以我只需要這樣做:

const replayAnimations = () => {
  document.getAnimations().forEach((anim) => {
    anim.cancel();
    anim.play();
  });
};

但在大多數情況下,人們可能會想選擇他們要重新啟動的動畫…

getAnimations 會回傳一堆看起來像這樣的 CSSAnimation 和 CSSTransition 物件:

animationName: "fade"
currentTime: 1500
effect: KeyframeEffect
  composite: "replace"
  pseudoElement: null
  target: path.line.yellow
finished: Promise {<fulfilled>: CSSAnimation}
playState: "finished"
ready: Promise {<fulfilled>: CSSAnimation}
replaceState: "active"
timeline: DocumentTimeline {currentTime: 135640.502}

...etc

因此,你可以使用 animationName 和 target 屬性來選擇你想要的動畫(儘管方式有點繞)。


編輯

這裡有一個方便的函數,它可能更適合只使用 Document.getAnimations,並加入 TypeScript 作為示範:

// restart animations on a given dom element
export const restartAnimations = (element: Element): void => {
  for (const animation of document.getAnimations()) {
    if (
      animation.effect instanceof KeyframeEffect &&
      element.contains(animation.effect.target)
    ) {
      animation.cancel();
      animation.play();
    }
  }
};

答案#4

  1. 將動畫實作為 CSS 描述符
  2. 將描述符添加到元素以開始動畫
  3. 使用 animationend 事件處理函數在動畫完成時移除描述符,以便下次想重新啟動動畫時可以再次添加。

HTML

<div id="animatedText">
    Animation happens here
</div>

<script>
  function startanimation(element) {
    element.classList.add("animateDescriptor");
    element.addEventListener( "animationend",  function() {
      element.classList.remove("animateDescriptor");    
    } );
  }
</script>

<button onclick="startanimation( 
  document.getElementById('animatedText') )">
    Click to animate above text
</button>

CSS

@keyframes fadeinout {  
    from { color: #000000; }    
    25% {color: #0000FF; }  
    50% {color: #00FF00; }      
    75% {color: #FF0000; }  
    to { color : #000000; } 
}   
        
.animateDescriptor {    
    animation: fadeinout 1.0s;  
}   

在這裡試試看:jsfiddle