使用 mouseover 和 mouseout 時避免生澀的動畫 (Avoiding jerky animation when using mouseover and mouseout)


問題描述

使用 mouseover 和 mouseout 時避免生澀的動畫 (Avoiding jerky animation when using mouseover and mouseout)

我正在使用 Web Animation API 創建一個簡單的動畫,當用戶在 target 上移動鼠標時,動畫應該從左到右開始,當用戶將鼠標移出 target 時,動畫應該得到反轉,target 應該從右向左移動。

當前如果用戶在動畫期間將鼠標移入/移出,動畫是生澀的,我沒有一個平滑的效果。

我想知道如何解決這個問題。

注意:目前我正在使用Web Animation API。但是在使用 CSS 關鍵幀動畫時也會出現同樣的問題。

我也嘗試使用以下解決方案解決此問題,這改善了情況,但仍然存在問題。這是一個現場示例 https://jsfiddle.net/x784xwoa/5/

var elm = document.getElementById("target");
var player = document.getElementById("target");

elm.addEventListener('mouseover', function(event) {
  console.log('mouseover', player.playState, 'animate');
  player = elm.animate(
    [{
      left: "0px",
      boxShadow: 'rgba(0, 0, 0, 0.5) 0px 0px 0px 0px'
    }, {
      left: "100px",
      boxShadow: 'rgba(0, 0, 0, 0.9) 50px 150px 100px 0px'
    }], {
      duration: 3000,
      direction: "normal",
      fill: "forwards",
      iterations: 1
    }
  );
});

elm.addEventListener('mouseout', function(event) {
  console.log('mouseout', player.playState, 'reverse');
  player.reverse();
});
#target {
  position: relative;
  top: 0;
  left: 0;
  width: 100px;
  height: 150px;
  background‑color: red;
}
<div id="target"></div>


參考解法

方法 1:

I've always had success using mouseenter / mouseleave rather than mouseover / mouseout.

Though they operate the same way, however, the mouseenter event only triggers when the mouse pointer enters the selected element. The mouseover event is triggered if a mouse pointer enters any child elements as well.

方法 2:

I was able to solve this issue using the following script adding some logic to check playState. In case you have a better solution, please post it as answer as I would be really interested to have your feedback.

   document.addEventListener("DOMContentLoaded", function (event) {
            var elm = document.getElementById("target");
            var player = null;



            elm.addEventListener('mouseenter', function (event) {
                if (player === null) {
                    player = elm.animate(
                      [{
                          left: "0px",
                          boxShadow: 'rgba(0, 0, 0, 0.5) 0px 0px 0px 0px'
                      }, {
                          left: "100px",
                          boxShadow: 'rgba(0, 0, 0, 0.9) 50px 150px 100px 0px'
                      }], {
                          duration: 3000,
                          direction: "normal",
                          fill: "forwards",
                          iterations: 1
                      }
                    );
                }
                else if (player.playState === 'running') {
                    player.reverse();
                }
                else if (player.playState === 'finished') {
                    player.reverse();

                }
            });

            elm.addEventListener('mouseout', function (event) {
                if (player.playState === 'running' || player.playState === 'finished') {
                    player.reverse();
                }
            });

            setInterval(function () {
                if (player) {
                    console.log(player.playState);
                }
            }, 1000);


        });
        #target {
            position: relative;
            top: 0;
            left: 0;
            width: 100px;
            height: 150px;
            background‑color: red;
        }
    <div id="target"></div>

方法 3:

Every time the mouseover event is triggered you make a new animation for the element. Avoid this by creating the animation beforehand, and pausing it until it is used.

I also replaced player.reverse(); with player.playBackRate = (‑)1;. I'm not sure why that also caused problems.

var elm = document.getElementById("target");
var player = elm.animate(
  [{
    left: "0px",
    boxShadow: 'rgba(0, 0, 0, 0.5) 0px 0px 0px 0px'
  }, {
    left: "100px",
    boxShadow: 'rgba(0, 0, 0, 0.9) 50px 150px 100px 0px'
  }], {
    duration: 3000,
    direction: "normal",
    fill: "forwards",
    iterations: 1
  }
);
player.pause();

elm.addEventListener('mouseover', function(event) {
  player.playbackRate = 1;
  player.play();
});

elm.addEventListener('mouseout', function(event) {
  player.playbackRate = ‑1;
});
#target {
  position: relative;
  top: 0;
  left: 0;
  width: 100px;
  height: 150px;
  background‑color: red;
}
<div id="target"></div>

The only issue that remains is that the mouseout event doesn't fire when the element moves from underneath the mouse. It only fires when the mouse is moved.

(by GibboKrfornalGibboKFloris)

參考文件

  1. Avoiding jerky animation when using mouseover and mouseout (CC BY‑SA 2.5/3.0/4.0)

#animation #javascript #css #web-animations






相關問題

Iphone app PNG 序列動畫 - 如何在不崩潰的情況下以最佳方式使用 OPENgle (Iphone app PNG sequence animation - How to use OPENgle optimally without crashing)

jquery切換幻燈片和切換旋轉動畫 (jquery toggle slide and toggle rotation animate)

如何在三次貝塞爾方法上禁用 css3 過渡鼠標離開效果? (How to disable css3 transition mouseleave effect on cubic-bezier method?)

Android:故事書(動畫、聲音、圖片) (Android: Storybooks (animation, sounds, pictures))

JQuery 動畫凌亂 (JQuery Animations Messy)

拉斐爾對角變換對象和無限setIntervals (Raphael transform object diagonally and infinite setIntervals)

使用 mouseover 和 mouseout 時避免生澀的動畫 (Avoiding jerky animation when using mouseover and mouseout)

在 C 中復制 Spinrite 動畫效果 (Replicating Spinrite Animation Effect in C)

將樣式作為參數傳遞給 jquery animate (passing style as argument to jquery animate)

如何設置 UIButton 的圖像並隨後將其刪除(動畫) (How to setImage of a UIButton and subsequently remove it (animation))

單擊消息後的 MessageKit 動畫 (MessageKit animation after click on message)

連續貝塞爾動畫,不繼承變化時的緩動功能 (Continuous bezier animation without inheriting easing-function on change)







留言討論