Change easing functions on animations in jQuery qu

2019-03-02 15:40发布

问题:

I have an animation linked to scroll position. Whenever the the user scrolls up or down, an animation is triggered for that position to move an element within the view window. If the user scrolls farther, these animations need to queue so that the element moves smoothly along the path.

var target = getAnimation();
var props = {
    left: [target.x, target.easing],
    top: target.y
};

$("#ball").animate(props, 400, "easeInOutQuad");

The problem with this is that when multiple animations get queued, the ball slows and speeds up in a bad way. What I'd like to do is something like this:

var target = getAnimation();
var props = {
    left: [target.x, target.easing],
    top: target.y
};

var ball = $("#ball"), queue = ball.queue();

if(ball.queue().length) {
    for(var i = 1, len = queue.length; i < len; i++) {
        //modify all the other queued animations to use linear easing
    }
    ball.animate(props, 400, "easeOutQuad");
}
else {
    ball.animate(props, 400, "easeInQuad");
}

By starting with an easeIn function, using linear in the middle, and easeOut at the end, I get a much smoother animation. Is there anyway I can access and modify the animations in the queue?

Edit:

Here is a fiddle to demonstrate what I'm trying to achieve: https://jsfiddle.net/reesewill/mtepvguw/

In the fiddle, I am using linear easing, but I'd really like the general affect to be more like easeInOutQuad. However, because I allow queueing, I can't just apply that easing function without it messing up the whole effect (change the linear to easeInOutQuad and click queue a few times quickly to see). Thus, I need something like the above to create the general impression of easeInOutQuad.

回答1:

Note , $(selector).queue() returns a reference to the animation queue, an Array. This reference can be modified with standard array methods. See also .dequeue() .

Try utilizing

Array.prototype.splice()

Summary

The splice() method changes the content of an array by removing existing elements and/or adding new elements.

Syntax

array.splice(start, deleteCount[, item1[, item2[, ...]]]) Parameters

start

Index at which to start changing the array. If greater than the length of the array, actual starting index will be set to the length of the array. If negative, will begin that many elements from the end.

deleteCount

An integer indicating the number of old array elements to remove. If deleteCount is 0, no elements are removed. In this case, you should specify at least one new element. If deleteCount is greater than the number of elements left in the array starting at start, then all of the elements through the end of the array will be deleted.

itemN

The element to add to the array. If you don't specify any elements, splice() will only remove elements from the array.

Returns

An array containing the deleted elements. If only one element is removed, an array of one element is returned. If no elements are removed, an empty array is returned.

See also Array.prototype.concat()


var elem = $("body")
, msg = function() {
    return "<br />" 
           + "queue length:" 
           + $(this).queue("abc").length
  };

elem.queue("abc", [
  function(next) {
    $(this).append(msg.call(this));
    next()
  },
  function(next) {
    $(this).append(msg.call(this));
    next()
  },
  function(next) {
    $(this).append(msg.call(this));
    next()
  }
]);

elem.append(msg.call(elem));

// do stuff, 
// replace `function` within `abc` queue,
// change `easing` options within replacement function 
elem.queue("abc").splice(1, 1, function(next) {
  $(this).append("<br />" 
                 + "`function` at index `1` within `abc` queue " 
                 + "replaced with new `function`" 
                 + msg.call(this));
  next()
});

elem.append("<br />" 
            + "after `.splice()` , before `.concat()`" 
            + msg.call(elem));
// do stuff,
// `concat` functions onto `abc` queue`
var arr = elem.queue("abc").concat(
  function(next) {
    $(this).append(msg.call(this));
    next()
  }, function(next) {
    $(this).append(msg.call(this));
    next()
  }, function() {
    $(this).append(msg.call(this) 
                   + "<br />" 
                   + "done");
  }
);

elem.queue("abc", arr);

elem.append("<br />" 
            + "after `.concat()`"
            + msg.call(elem));

elem.dequeue("abc");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>



回答2:

i tried, you can do it with create new (re-ordered) queue

download source http://api.jquery.com/queue/
Example: Set a queue array to delete the queue.

and replace start event with my, its worked.

But functions in queue are stored in array of functions. You need to know order of original queue of animations which you want to changed :( Or you can create new optimalized queue.

$( "#start" ).click(function() {
  $( "div" )
    .show( "slow" )
    .animate({ left: "+=50" }, 5000 )
    .animate({ top: "+=50" }, 5000 )
    .queue(function() {
      $( this ).addClass( "newcolor" ).dequeue();
    })
    .animate({ left: '-=50' }, 1500 )
    .queue(function() {
      $( this ).removeClass( "newcolor" ).dequeue();
    })
    .slideUp();


    // get current queue
    var currQueue = $( "div" ).queue( "fx");

    // create new queue and change order or add/remove animations
    var newQueue = [];
      newQueue.push(currQueue[1]);
      newQueue.push(currQueue[3]); // changed
      newQueue.push(currQueue[2]); // changed
      newQueue.push(currQueue[5]);

    // set new queue to element
    $("div").queue("fx", newQueue);

    console.log($("div").queue("fx"));
}); 

more info found in jquery documentation

.queue( [queueName ], newQueue )
Description: Manipulate the queue of functions to be executed, once for each matched element.

important is second parameter newQueue

i hope it helps