我可以在 jQuery 中为每个动画步骤实现回调吗?

发布于 2024-08-03 07:22:40 字数 458 浏览 10 评论 0原文

我想在我的网站中实现一个动画:

  • 需要更新多个 DOM 元素。
  • 每个 DOM 元素都有自己的动画路径(取决于它们的位置)
  • 并且仍然具有缓动效果。

如果我为每个元素调用 jQuery 的 animate() 函数(队列: false),它将使每个元素与其余元素稍微不同步。这是有道理的,因为有多个计时器在运行。

我可以只有一个计时器事件,并为每个动画步骤提供回调吗? 像这样的东西:

jQuery.fx.timeline( from, to, easing, function( step, total ) {

      var percentage = step / total;
      // ...update DOM elements based on the percentage of the animation

} );

I'd like to implement an animation in my site which:

  • needs to update multiple DOM elements.
  • each DOM element has it's own animation path (depends on their position)
  • and still have an easing effect.

If I call jQuery's animate() function for each element (with queue: false), it will make each element move slightly out of sync with the rest. Makes sense, since there are multiple timers running.

Can I have just one timer event, with a callback for each animation step?
Something like:

jQuery.fx.timeline( from, to, easing, function( step, total ) {

      var percentage = step / total;
      // ...update DOM elements based on the percentage of the animation

} );

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心意如水 2024-08-10 07:22:40

看看这篇文章: http://james.padolsey.com/javascript/ fun-with-jquerys-animate/

非常清晰,非常简单!

look at this article: http://james.padolsey.com/javascript/fun-with-jquerys-animate/

very clear, very easy!

两相知 2024-08-10 07:22:40

JavaScript 中的所有计时器都基于原生普通老式 JavaScript 函数 setInterval()setTimeout()。甚至 jQuery 在内部也使用了它。

同步计时器的技巧是确保只有一个 setInterval() 被调用,所以我们自己构建一些东西。

动画可以设计为:

  • 有 10 个步骤,每个步骤间隔 30ms。
  • 整个动画需要 300 毫秒。
  • 在每一步,可以计算当前进度/百分比:

    var Percentage = ( currentStep / TotalSteps );

现在,每次通过 setInterval() 调用您的函数时,您都可以一次性将所有 DOM 元素设置到正确的位置。要找出每个动画帧中元素应位于的位置,您可以使用:

var diff       = ( to - from );
var stepValue  = from + diff * percentage;

可以直接调用 jQuery 缓动函数,最终语句变为:

var stepValue  = jQuery.easing[ easingMethod ]( percentage, 0, from, diff );

我已将其变成一个类:

/**
 * Animation timeline, with a callback.
 */
function AnimationTimeline( params, onstep )
{
  // Copy values.

  // Required:
  this.from     = params.from || 0;         // e.g. 0%
  this.to       = params.to   || 1;         // e.g. 100%
  this.onstep   = onstep || params.onstep;  // pass the callback.

  // Optional
  this.steps    = params.steps    || 10;
  this.duration = params.duration || 300;
  this.easing   = params.easing   || "linear";

  // Internal
  this._diff  = 0;
  this._step  = 1;
  this._timer = 0;
}

jQuery.extend( AnimationTimeline.prototype, {

  start: function()
  {
    if( this.from == this.to )
      return;

    if( this._timer > 0 )
    {
      self.console && console.error("DOUBLE START!");
      return;
    }

    var myself  = this;    
    this._diff  = ( this.to - this.from );
    this._timer = setInterval( function() { myself.doStep() }, this.duration / this.steps );
  }

, stop: function()
  {
    clearInterval( this._timer );
    this._timer = -1;
    this._queue = [];
  }

, doStep: function()
  {
    // jQuery version of: stepValue = from + diff * percentage;
    var percentage = ( this._step / this.steps );
    var stepValue  = jQuery.easing[ this.easing ]( percentage, 0, this.from, this._diff );

    // Next step
    var props = { animationId: this._timer + 10
                , percentage: percentage
                , from: this.from, to: this.to
                , step: this._step, steps: this.steps
                };
    if( ++this._step > this.steps )
    {
      stepValue = this.to;  // avoid rounding errors.
      this.stop();
    }

    // Callback
    if( this.onstep( stepValue, props ) === false ) {
      this.stop();
    }
  }
});

现在您可以使用:

var el1 = $("#element1");
var el2 = $("#element2");

var animation = new AnimationTimeline( {
    easing: "swing"
  , onstep: function( stepValue, animprops )
    {
      // This is called for every animation frame. Set the elements:
      el1.css( { left: ..., top: ... } );
      el2.css( { left: ..., top: ... } );
    }
  });

// And start it.
animation.start();

添加暂停/resume 是给读者的一个练习。

All timers in JavaScript are based on the native plain old school JavaScript function setInterval() or setTimeout(). Even jQuery uses this internally.

The trick to synchronize timers, is making sure there is only one setInterval() is invoked, so build something ourselves.

An animation can be designed with:

  • have 10 steps, each with an interval of 30ms.
  • The total animation takes 300ms.
  • At each step, the current progress/percentage can be calculated:

    var percentage = ( currentStep / totalSteps );

Now, each time your function is called by setInterval(), you can set all DOM elements at once to the correct positions. To find out where an element should be at each animation frame, you use the:

var diff       = ( to - from );
var stepValue  = from + diff * percentage;

The jQuery easing functions can be called directly, and the final statement becomes:

var stepValue  = jQuery.easing[ easingMethod ]( percentage, 0, from, diff );

I've turned this into a class:

/**
 * Animation timeline, with a callback.
 */
function AnimationTimeline( params, onstep )
{
  // Copy values.

  // Required:
  this.from     = params.from || 0;         // e.g. 0%
  this.to       = params.to   || 1;         // e.g. 100%
  this.onstep   = onstep || params.onstep;  // pass the callback.

  // Optional
  this.steps    = params.steps    || 10;
  this.duration = params.duration || 300;
  this.easing   = params.easing   || "linear";

  // Internal
  this._diff  = 0;
  this._step  = 1;
  this._timer = 0;
}

jQuery.extend( AnimationTimeline.prototype, {

  start: function()
  {
    if( this.from == this.to )
      return;

    if( this._timer > 0 )
    {
      self.console && console.error("DOUBLE START!");
      return;
    }

    var myself  = this;    
    this._diff  = ( this.to - this.from );
    this._timer = setInterval( function() { myself.doStep() }, this.duration / this.steps );
  }

, stop: function()
  {
    clearInterval( this._timer );
    this._timer = -1;
    this._queue = [];
  }

, doStep: function()
  {
    // jQuery version of: stepValue = from + diff * percentage;
    var percentage = ( this._step / this.steps );
    var stepValue  = jQuery.easing[ this.easing ]( percentage, 0, this.from, this._diff );

    // Next step
    var props = { animationId: this._timer + 10
                , percentage: percentage
                , from: this.from, to: this.to
                , step: this._step, steps: this.steps
                };
    if( ++this._step > this.steps )
    {
      stepValue = this.to;  // avoid rounding errors.
      this.stop();
    }

    // Callback
    if( this.onstep( stepValue, props ) === false ) {
      this.stop();
    }
  }
});

And now you can use:

var el1 = $("#element1");
var el2 = $("#element2");

var animation = new AnimationTimeline( {
    easing: "swing"
  , onstep: function( stepValue, animprops )
    {
      // This is called for every animation frame. Set the elements:
      el1.css( { left: ..., top: ... } );
      el2.css( { left: ..., top: ... } );
    }
  });

// And start it.
animation.start();

Adding a pause/resume is an exercise for the reader.

皓月长歌 2024-08-10 07:22:40

一个简单的答案就可以做到。也许有人会像我一样搜索它。

我们可以在动画函数中使用“step”属性。

$(obj).animate(
    {
        left: 0
    },
    {
        duration: 50,
        step: function( currentLeft ){
            console.log( "Left: ", currentLeft );
        }
    }
 );

因此,对于每一步,这将记录当前的左侧位置

A simple answer to do it. Maybe someone will search it as i did.

We can user the "step" attribute in the animation function.

$(obj).animate(
    {
        left: 0
    },
    {
        duration: 50,
        step: function( currentLeft ){
            console.log( "Left: ", currentLeft );
        }
    }
 );

So for each step, this will log the current left position

好久不见√ 2024-08-10 07:22:40

您检查过 jquery 队列 吗?

您可以对动画进行排队并为每个动画设置回调,我认为如果您稍微使用它,您就可以实现您想要的。

希望有帮助,思南。

did you check jquery queue?

You can queue your animations and set a callback on each of them, I think if you play little bit with it you can achieve what you want.

Hope it helps, Sinan.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文