Javascript动画的行为不符合预期

Javascript animation does not behave in intended way

本文关键字:不符合 动画 Javascript      更新时间:2024-03-01

我想创建一个简单的动画,其中矩形的长度在"mouseover"事件发生时平滑地变为其值的一半,在"mouse out"事件发生后再次变为双倍。如果鼠标移动缓慢,下面的代码会起作用,但如果鼠标移动迅速,则不会起作用。如果鼠标快速移动,矩形就会卡住。请建议如何克服这个问题。

<body>
    <svg id="svg" width="600" height="100">
        <rect id="myrect" width="600" height="100" fill="green">
     </svg>
     <script>
        svg = document.getElementById("svg");
        var w = 600;
        var step = 10;
        
        svg.addEventListener("mouseover", function(){ 
            function anim ()    {
                w -= step;
                if( w >= 300)    {
                    myrect = document.getElementById("myrect");
                    myrect.setAttribute("width", w);
                    requestAnimationFrame(anim);            
                }
            }
            anim();
        });
        
        svg.addEventListener("mouseout", function(){ 
            function anim ()    {
                w += step;
                if( w <= 600)    {
                    myrect = document.getElementById("myrect");
                    myrect.setAttribute("width", w);
                    requestAnimationFrame(anim);            
                }
            }
            anim();
        });
    </script>
</body>

今天,请不要将JavaScript用于此类动画。CSS转换就是为此而设计的,它们显示出更好的性能,因为大多数浏览器可以在显卡上比CPU更快地计算它们。

欲了解更多信息,请参阅W3C学校关于CSS转换

因此,您的示例的改进版和更短的版本看起来像

#myrect {
  transition: transform 0.5s ease;
}
#myrect:hover {
  transform: scale(0.5, 1.0);
}
<svg id="svg" width="600" height="100">
  <rect id="myrect" width="600" height="100" fill="green" />
</svg>

注意:您似乎无法像以前那样通过简单的CSS为SVG的"width"属性设置动画。为了便于处理,您可以使用translate属性并将其缩放到宽度的50%。

(好吧,根据SVG标准-节属性的"宽度"可以用更强制的SVG动画逻辑进行动画化,但CSS看起来更安静,这些知识也可以应用于HTML元素:-)

以下代码的简短解释:

动画过程统一在一个单一的函数中,可以根据direction参数值在两个方向上工作。鼠标事件只是改变动画的方向。变量animActive防止了requestAnimationFrame的双重调用,使方向变化平滑。

<body>
    <svg id="svg" width="600" height="100">
        <rect id="myrect" width="600" height="100" fill="green">
     </svg>
     <script>
        svg = document.getElementById("svg");
        var w = 600;
        var step = 10;
        var direction;
        var animActive = false;
        
        svg.addEventListener("mouseover", function(){ 
            direction = true;
            if (!animActive)
              requestAnimationFrame(anim);
        });
        
        svg.addEventListener("mouseout", function(){ 
            direction = false;
            if (!animActive)
              requestAnimationFrame(anim);
        });
       
       function anim(){
         if (direction){
            if( w > 300){
                animActive = true;
                w -= step;
                myrect = document.getElementById("myrect");
                myrect.setAttribute("width", w);
                requestAnimationFrame(anim);
            }
            else
                animActive = false;
         }
         else{
            if( w < 600){
                animActive = true;
                w += step;
                myrect = document.getElementById("myrect");
                myrect.setAttribute("width", w);
                requestAnimationFrame(anim);            
            }
           else
               animActive = false;
         }
       }
    </script>
</body>