问题
This is a bit of a generic question.
If I have a jQuery animation on an element #elm, I can stop it using $('#elm').stop()
Usually the animation will have a nice easeIn, easeOut (like the default 'swing'). Calling 'stop()' stops it right away, on the spot, looking a bit clunky. Calling $('#elm').stop(true,true) makes it finish the animation right away, all the way to the end point.
Is there a generic approach to tell an element to "change the running animation so that it will stop 'soon' and 'nearby', but use the easeOut as defined first" ?
curious, *-pike
回答1:
Pike,
I don't know of a totally generic way to do a "gentle_stop" - one that will operate on any animation regardless of how it was intialised.
The code below, defines the function gentleStoppable() which is, in effect, a 4-parameter version of jQuery's own .animate( properties, options ) method. The extra two paramters specify the "gentle-stop" phase.
Here's the function :
function gentleStoppable($jQ, animProps, animOptions, stopProps, stopOptions) {
var namespace = 'gentleStop';
var dfltStopOptions = {
duration: 'slow',//override with stopOptions.duration .
easing: 'easeOutCubic',//override with stopOptions.easing . (See also the safety check applied after extending dfltStopOptions below).
queue: namespace
};
animProps = animProps || {};
animOptions = animOptions || {};
stopProps = stopProps || {};
stopOptions = stopOptions || {};
$jQ.each(function(i, elem) {
var $elem = $(elem);
function killCustomEvent() { $elem.off(namespace); }
var C = $.Callbacks('once').add(killCustomEvent);
if(animOptions.complete) {
C.add(animOptions.complete);
}
animOptions.complete = C.fire;
stopProps = $.extend({}, animProps, stopProps);
stopOptions = $.extend({}, animOptions, dfltStopOptions, stopOptions);
stopOptions.easing = ($.easing && $.easing[stopOptions.easing] ) ? stopOptions.easing : 'swing';//just in case what's specifified is unavailable.
$elem.on(namespace, function() {//custom event
killCustomEvent();
C.remove(killCustomEvent);//prevent killCustomEvent being called twice.
$elem.stop(true,false).animate(stopProps, stopOptions).dequeue(namespace);
}).animate(animProps, animOptions);
});
}
Initiate a gentleStoppable animation as follows :
var animProps = {
left: '300px'
};
var animOptions = {
duration: 2000,
complete: function() {
console.log('complete');
}
};
var stopProps = {
left: '+=15px'
};
var stopOptions = {
duration: 500,
};
gentleStoppable($e1, animProps, animOptions, stopProps, stopOptions);
Then to perform a gentle stop :
$("#elem").trigger('gentleStop');
Demo
As it stands, the function isn't perfect and I have put it through only limited testing. Here are the known issues/improvements:
Direction: A stopProps property of the form
xxx:+=15pxwill unconditionally add 15px in the gentlestop phase, even if it is in the wrong direction. For example, if the corresponding animProps property wasxxx:30pxthen+=15pxwould assume the target value of30pxwas being approached from below. Similaraly, a value of-=15pxwould assume the corresponding target value was being approached from above. An improvement to gentleStoppable() would automtically adjust each stopProps property to allow its corresponding animProps property to be approached from below OR above.Overshoot: A stopProps property of the form
xxx:+=15pxwill unconditionally add 15px in the gentlestop phase, even if +15px takes the gentle animation beyond what is specified in the corresponding animProps property. This will tend to occur if the animation is stopped near its natural end. An improvement to gentleStoppable() would automtically prevent each stopProps' property from causing its corresponding animProps property being exceeded.Auto-caluculation: An undoubted improvement would be for gentleStoppable() to calculate stopProps values for itself, based on animProps. This would make the function general, simpler to use and, written correctly, would effectively fix the Direction and Overshoot issues.
With a little more thought the code could be refactored as a jQuery plugin, which would be more convenient as it would allow method chaining and avoid the rather clumsy
.trigger(...)to perform a gentle stop.
If this is of any use, then please use it.
来源:https://stackoverflow.com/questions/13442604/jquery-animation-stop-triggering-easeout