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

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

Javascript添加/刪除動畫類,只動畫一次

Javascript添加/刪除動畫類,只動畫一次

千萬里不及你 2021-11-04 15:08:42
試圖構建一個時間選擇器,它應該為輸入的變化設置動畫。我想我會通過從 CSS 中添加和刪除動畫類來做到這一點。問題是,它只在第一次有效。我嘗試設置一個間隔開始,在一定時間后刪除類,略高于動畫持續時間,但是每次單擊都會減少動畫的動畫時間,并且通過第三次或第四次單擊,它沒有更長的動畫。然后我只是選擇檢查該類是否存在,刪除它,然后添加它。確保每次都從頭開始。但現在它只是第一次動畫。HTML:    <div id="wrapper">      <div id="uphour"></div>      <div id="upminute"></div>      <div id="upampm"></div>      <div class="animated">        <div id="hour" data-hour="1">2</div>      </div>      <div class="animated">        <div id="minute" data-minute="1">50</div>      </div>      <div class="animated">        <div id="ampm" data-minute="AM">AM</div>      </div>      <div id="downhour"></div>      <div id="downminute"></div>      <div id="downampm"></div>      </div>..它是 swapAMPM 函數(在 Javascript 的末尾)我目前沒有按預期行事。關于為什么我會遇到這種行為的任何建議?我缺少一些最佳實踐嗎?
查看完整描述

3 回答

?
MM們

TA貢獻1886條經驗 獲得超2個贊

我想這就是你在香草中的做法


gugateider 是對的,你需要一個 setTimout,有 AnimationEvent API 但它不完全支持。


下面是一個簡化的方法:


不需要事件監聽器或收集 ID


更新:

包括去抖動以停止對同一按鈕的多次點擊

調整超時(添加超時以便值在視圖外發生變化以產生數字實際旋轉的錯覺,AnimationEvent 無法檢測您是否已完成動畫。)

<div class="wrapper">


  <div id="hour" class="unit">

    <div class="plus button" onClick="pressedButton(event);">+</div>

    <div class="value"><div>10</div></div>

    <div class="minus button" onClick="pressedButton(event);">-</div>

  </div>


    <div id="minute" class="unit">

    <div class="plus button"  onClick="pressedButton(event);">+</div>

      <div class="value"><div>36</div></div>

    <div class="minus button"  onClick="pressedButton(event);">-</div>

  </div>


    <div id="meridiem" class="unit">

    <div class="plus button"  onClick="pressedButton(event);">+</div>

      <div class="value"><div>AM</div></div>

    <div class="minus button"  onClick="pressedButton(event);">-</div>

  </div>




</div>


.wrapper {

  display: flex;

  flex-flow: row no-wrap;

  justify-content: space-between;

  align-items: center;

  width: 200px;

  height: 200px;

  margin: 100px auto;

  background: red;

  padding: 20px;

}


.unit {

  display: flex;

  flex-flow: column;

  justify-content: space-between;

  align-items: space-between;

  height: 100%;

  position: relative;

}


.button {

  border: 2px solid black;

  height: 50px;

  width: 50px;

  cursor: pointer;

  display: flex;

  justify-content: center;

  align-items: center;

  background: grey;


  &:hover {

    opacity: 0.8;

  }


}



.value {

  border: 2px solid black;

  height: 50px;

  width: 50px;

  font-family: sans-serif;

  font-size: 20px;

  display: flex;

  justify-content: center;

  align-items: center;

  background: lightgrey;

    overflow: hidden;

}


.animate {

  top: 0;

  position: relative;

  overflow: hidden;

  animation-name: downandout;

  animation-duration: 1s;

  animation-iteration-count: 1;

  transition-timing-function: ease-in-out;


  &--reverse {

    animation-direction: reverse;

  }

}





 @keyframes downandout {

   0%  {top: 0}

   50% {top: 50px}

   51% {top: -50px}

   100%  {top: 0}

}

debounce = function(func, wait, immediate) {

  var timeout;

  return function() {

    var context = this,

      args = arguments;

    var later = function() {

      timeout = null;

      if (!immediate) func.apply(context, args);

    };

    var callNow = immediate && !timeout;

    clearTimeout(timeout);

    timeout = setTimeout(later, wait);

    if (callNow) func.apply(context, args);

  };

}


pressedButton = function($event) {

  $event.preventDefault();


  // debouncedFn to stop multiple clicks to the same button

  var debouncedFn = debounce(function() {

    // All the taxing stuff you do

    const target = $event.target;

    const elm = target.parentNode.children[1];


    let direction;


    // clone the element to restart the animation

    const newone = elm.cloneNode(true);

    // add the first animate

    newone.children[0].classList.add("animate");


    // What button was pressed

    if (target.classList.contains("minus")) {

      direction = "down";

    } else {

      direction = "up";

    }


    // direction of animation

    if (direction === "down") {

      newone.children[0].classList.add("animate--reverse");

    } else {

      newone.children[0].classList.remove("animate--reverse");

    }


    // add the new element to the DOM

    elm.parentNode.replaceChild(newone, elm);


    // change value after half of the animation has completed

    setTimeout(function() {

      switch (target.parentNode.id) {

        case "hour":

        case "minute":

          if (direction === "down") {

            newone.children[0].innerText--;

          } else {

            newone.children[0].innerText++;

          }

          break;


        case "meridiem":

          if (newone.children[0].innerText === "PM") {

            newone.children[0].innerText = "AM";

          } else {

            newone.children[0].innerText = "PM";

          }

      }

    }, 100);

  }, 250);


  // Call my function

  debouncedFn();


};

https://codepen.io/eddy14u/pen/VwZJmdW


查看完整回答
反對 回復 2021-11-04
?
明月笑刀無情

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

您可以使用動畫迭代事件偵聽器來檢測動畫何時結束,并正確刪除您的類。為此,動畫迭代必須設置為無限。在我的更改中,我還利用classList元素的屬性從元素中添加/刪除類。


注意:如果沒有至少 1 次迭代,動畫迭代事件將永遠不會觸發,因此代碼將無法運行!


編輯:瀏覽器支持classList是最近的,所以如果你需要支持舊瀏覽器,你可以回退到不同的解決方案,或者添加一個classList polyfill


首先,我們需要一個函數來檢測瀏覽器支持哪個動畫迭代事件:


function whichAnimationEvent(){

  var el = document.createElement("fakeelement");


  var animations = {

    "animation"      : "animationiteration",

    "OAnimation"     : "oAnimationIteration",

    "MozAnimation"   : "animationiteration",

    "WebkitAnimation": "webkitAnimationIteration"

  };


  for (let t in animations){

    if (el.style[t] !== undefined){

      return animations[t];

    }

  }

}

接下來,我們需要為該事件添加一個事件偵聽器,當迭代觸發時,我們從元素的 中刪除該類classList,如下所示:


ampmEl.addEventListener(whichAnimationEvent(),function(){

  console.log('ampmEl event listener fired')

  ampmEl.classList.remove('animateStart');

});

接下來,我們將swapAMPM函數更改為在執行交換之前使用add元素的方法classList添加類,使其具有動畫效果。


function swapAMPM() {

  let value = ampmEl.innerHTML;

  ampmEl.classList.add('animateStart');

  if (value === "AM") {

      value = "PM";

      ampmEl.innerHTML = value;

      console.log("Changed from AM");

  } else  {

    value = "AM";

    ampmEl.innerHTML = value;

    console.log("Changed from PM");

  }

}

最后,我們需要更新 css 以進行infinite動畫迭代,以便觸發我們的事件。


.animateStart {

  -webkit-animation-name: downandout; /* Safari 4.0 - 8.0 */

  animation-name: downandout;

  -webkit-animation-duration: 250ms; /* Safari 4.0 - 8.0 */

  animation-duration: 250ms;

  -webkit-animation-iteration-count: infinite;

  animation-iteration-count: infinite;

  transition-timing-function: cubic-bezier(1,0,0,1);

}


查看完整回答
反對 回復 2021-11-04
?
飲歌長嘯

TA貢獻1951條經驗 獲得超3個贊

我知道 setTimeout 不是在那里使用的最佳選擇,但是由于您已經完成了很多工作,您可以嘗試用以下代碼替換 swapAMPM 函數:


function swapAMPM() {

 let value = ampmEl.innerHTML;

 if (ampmEl.hasAttribute("class")) {

     ampmEl.removeAttribute("class");

 }

 setTimeout( () => { 

     ampmEl.setAttribute("class", "animateStart");

     if (value === "AM") {

      value = "PM";

      ampmEl.innerHTML = value;

      console.log("Changed from AM");

     } else  {

        value = "AM";

        ampmEl.innerHTML = value;

        console.log("Changed from PM");

    } 

 }, 150);

}


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

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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