問題描述
使用 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 GibboK、rfornal、GibboK、Floris)