使用 mouseover 和 mouseout 时避免抖动动画
Avoiding jerky animation when using mouseover and mouseout
我正在使用 Web Animation API 创建一个简单的动画,这样当用户将鼠标移到 target
上时,动画应该从左到右开始,当用户将鼠标移开时target
,动画应该反转,target
应该从右向左移动。
目前如果用户在动画中移动鼠标in/out,动画会出现抖动,我没有流畅的效果。
我想知道如何解决这个问题。
注意:目前我使用的是网页动画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>
我总是使用 mouseenter / mouseleave 而不是 mouseover / mouseout.
虽然它们的操作方式相同,但是 mouseenter
事件仅在鼠标指针进入所选元素时触发。如果鼠标指针也进入任何子元素,则会触发 mouseover
事件。
我能够使用以下脚本添加一些逻辑来检查 playState
来解决这个问题。
如果您有更好的解决方案,请 post 作为答案,因为我真的很想收到您的反馈。
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>
每次触发鼠标悬停事件时,您都会为该元素制作一个新动画。通过预先创建动画并暂停它直到使用它来避免这种情况。
我也用player.playBackRate = (-)1;
替换了player.reverse();
。我不确定为什么这也会导致问题。
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>
唯一剩下的问题是当元素从鼠标下方移动时,mouseout 事件不会触发。它只在鼠标移动时触发。
我正在使用 Web Animation API 创建一个简单的动画,这样当用户将鼠标移到 target
上时,动画应该从左到右开始,当用户将鼠标移开时target
,动画应该反转,target
应该从右向左移动。
目前如果用户在动画中移动鼠标in/out,动画会出现抖动,我没有流畅的效果。
我想知道如何解决这个问题。
注意:目前我使用的是网页动画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>
我总是使用 mouseenter / mouseleave 而不是 mouseover / mouseout.
虽然它们的操作方式相同,但是 mouseenter
事件仅在鼠标指针进入所选元素时触发。如果鼠标指针也进入任何子元素,则会触发 mouseover
事件。
我能够使用以下脚本添加一些逻辑来检查 playState
来解决这个问题。
如果您有更好的解决方案,请 post 作为答案,因为我真的很想收到您的反馈。
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>
每次触发鼠标悬停事件时,您都会为该元素制作一个新动画。通过预先创建动画并暂停它直到使用它来避免这种情况。
我也用player.playBackRate = (-)1;
替换了player.reverse();
。我不确定为什么这也会导致问题。
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>
唯一剩下的问题是当元素从鼠标下方移动时,mouseout 事件不会触发。它只在鼠标移动时触发。