亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

我可以使用 JS 等待多個 CSS 動畫嗎?

我可以使用 JS 等待多個 CSS 動畫嗎?

神不在的星期二 2021-10-29 15:03:17
我們有一種方法可以使用 JS 檢測動畫何時結束:const element = $('#animatable');element.addClass('being-animated').on("animationend", (event) => {  console.log('Animation ended!');});@keyframes animateOpacity {  0% {    opacity: 1;  }  100% {    opacity: 0;  }}@keyframes animatePosition {  0% {    transform: translate3d(0, 0, 0);  }  100% {    transform: translate3d(0, 15px, 0);  }}#animatable.being-animated {  animation: animateOpacity 1s ease 0s forwards, animatePosition 2s ease 0s forwards;}<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><div id="animatable">I'm probably being animated.</div>正如你所看到的,JS,理所當然地,因為我被這個animationend事件吸引住了,它告訴我“是的,動畫完成了”但不知道接下來會發生什么,我錯過了第二個。不是有動畫隊列嗎?當然,CSS 必須在系統中的某個地方注冊這些東西,然后才能在它們被觸發之前達到峰值。
查看完整描述

3 回答

?
守著一只汪

TA貢獻1872條經驗 獲得超4個贊

免責聲明:我不認為 jQuery 對回答這個問題很重要,如果其他人在看到這個答案后選擇依賴此代碼,它會損害負載和運行時性能。因此,我將使用 vanilla JavaScript 來回答,以幫助盡可能多的人,但如果您想使用 jQuery,您仍然可以應用相同的概念。


答:沒有動畫隊列,但您可以自己制作。


例如,您可以使用閉包和/或 a Map(在下面的代碼段中,我實際上使用 aWeakMap來幫助垃圾收集)將有關動畫的數據鏈接到目標元素。如果您將動畫狀態保存為true完成時,您可以檢查并最終在全部為 時觸發不同的回調true,或者調度您自己的自定義事件。我使用了自定義事件方法,因為它更靈活(能夠添加多個回調)。


以下代碼還可以幫助您避免在您實際上只關心幾個特定動畫的情況下等待所有動畫。它還應該讓您多次處理多個單獨元素的動畫事件(嘗試運行代碼段并單擊幾次框)


const addAnimationEndAllEvent = (() => {

  const weakMap = new WeakMap()


  const initAnimationsObject = (element, expectedAnimations, eventName) => {

    const events = weakMap.get(element)

    const animationsCompleted = {}

    for (const animation of expectedAnimations) {

      animationsCompleted[animation] = false

    }

    events[eventName] = animationsCompleted

  }


  return (element, expectedAnimations, eventName = 'animationendall') => {

    if (!weakMap.has(element)) weakMap.set(element, {})


    if (expectedAnimations) {

      initAnimationsObject(element, expectedAnimations, eventName)

    }


    // When any animation completes...

    element.addEventListener('animationend', ({ target, animationName }) => {

      const events = weakMap.get(target)

      

      // Use all animations, if there were none provided earlier

      if (!events[eventName]) {

        initAnimationsObject(target, window.getComputedStyle(target).animationName.split(', '), eventName)

      }

      

      const animationsCompleted = events[eventName]

      

      // Ensure this animation should be tracked

      if (!(animationName in animationsCompleted)) return


      // Mark the current animation as complete (true)

      animationsCompleted[animationName] = true


      // If every animation is now completed...

      if (Object.values(animationsCompleted).every(

        isCompleted => isCompleted === true

      )) {

        const animations = Object.keys(animationsCompleted)


        // Fire the event

        target.dispatchEvent(new CustomEvent(eventName, {

          detail: { target, animations },

        }))


        // Reset for next time - set all animations to not complete (false)

        initAnimationsObject(target, animations, eventName)

      }

    })

  }

})()


const toggleAnimation = ({ target }) => {

  target.classList.toggle('being-animated')

}


document.querySelectorAll('.animatable').forEach(element => {

  // Wait for all animations before firing the default event "animationendall"

  addAnimationEndAllEvent(element)


  // Wait for the provided animations before firing the event "animationend2"

  addAnimationEndAllEvent(element, [

    'animateOpacity',

    'animatePosition'

  ], 'animationend2')


  // Listen for our added "animationendall" event

  element.addEventListener('animationendall', ({detail: { target, animations }}) => {

    console.log(`Animations: ${animations.join(', ')} - Complete`)

  })


  // Listen for our added "animationend2" event

  element.addEventListener('animationend2', ({detail: { target, animations }}) => {

    console.log(`Animations: ${animations.join(', ')} - Complete`)

  })


  // Just updated this to function on click, so we can test animation multiple times

  element.addEventListener('click', toggleAnimation)

})

.animatable {

  margin: 5px;

  width: 100px;

  height: 100px;

  background: black;

}


@keyframes animateOpacity {

  0% {

    opacity: 1;

  }

  100% {

    opacity: 0;

  }

}


@keyframes animatePosition {

  0% {

    transform: translate3d(0, 0, 0);

  }

  100% {

    transform: translate3d(0, 15px, 0);

  }

}


@keyframes animateRotation {

  100% {

    transform: rotate(360deg);

  }

}


.animatable.being-animated {

  animation:

    animateOpacity 1s ease 0s forwards,

    animatePosition 1.5s ease 0s forwards,

    animateRotation 2s ease 0s forwards;

}

<div class="animatable"></div>

<div class="animatable"></div>


查看完整回答
反對 回復 2021-10-29
?
阿晨1998

TA貢獻2037條經驗 獲得超6個贊

它當然值得成為公認的答案。也就是說,我受到啟發,想看看一種不那么冗長的方法是否可行。這是我想出的。


這是不言自明的,但基本上概念是所有動畫屬性的索引都是相關的,我們可以使用它來查找最后完成的動畫的名稱。


const getFinalAnimationName = el => {

  const style = window.getComputedStyle(el)

  

  // get the combined duration of all timing properties

  const [durations, iterations, delays] = ['Duration', 'IterationCount', 'Delay']

    .map(prop => style[`animation${prop}`].split(', ')

      .map(val => Number(val.replace(/[^0-9\.]/g, ''))))

  const combinedDurations = durations.map((duration, idx) =>

    duration * iterations[idx] + delays[idx])

  

  // use the index of the longest duration to select the animation name

  const finalAnimationIdx = combinedDurations

    .findIndex(d => d === Math.max(...combinedDurations))

  return style.animationName.split(', ')[finalAnimationIdx]

}


// pipe your element through this function to give it the ability to dispatch the 'animationendall' event

const addAnimationEndAllEvent = el => {

  const animationendall = new CustomEvent('animationendall')

  el.addEventListener('animationend', ({animationName}) =>

    animationName === getFinalAnimationName(el) &&

      el.dispatchEvent(animationendall))

  return el

}


// example usage

const animatable = document.querySelector('.animatable')

addAnimationEndAllEvent(animatable)

  .addEventListener('animationendall', () => console.log('All animations have finished'))

.animatable {

  width: 50px;

  height: 50px;

  background-color: red;

  position: relative;

  left: 0;

  animation: 1.5s slidein, 1s fadein;

}


@keyframes slidein {

  0% { left: 100vw; }

  100% { left: 0; }

}


@keyframes fadein {

  0% { opacity: 0; }

  100% { opacity: 1; }

}

<div class="animatable"></div>


查看完整回答
反對 回復 2021-10-29
  • 3 回答
  • 0 關注
  • 154 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號