mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-04-29 05:15:38 +08:00
feat($animate): introduce the $animate.animate() method
This commit is contained in:
committed by
Igor Minar
parent
e5f4d7b10a
commit
02be700bda
@@ -170,6 +170,10 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|||||||
* page}.
|
* page}.
|
||||||
*/
|
*/
|
||||||
return {
|
return {
|
||||||
|
animate : function(element, from, to) {
|
||||||
|
applyStyles(element, { from: from, to: to });
|
||||||
|
return asyncPromise();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -628,9 +628,10 @@ angular.module('ngAnimate', ['ng'])
|
|||||||
}
|
}
|
||||||
|
|
||||||
var isSetClassOperation = animationEvent == 'setClass';
|
var isSetClassOperation = animationEvent == 'setClass';
|
||||||
var isClassBased = isSetClassOperation ||
|
var isClassBased = isSetClassOperation
|
||||||
animationEvent == 'addClass' ||
|
|| animationEvent == 'addClass'
|
||||||
animationEvent == 'removeClass';
|
|| animationEvent == 'removeClass'
|
||||||
|
|| animationEvent == 'animate';
|
||||||
|
|
||||||
var currentClassName = element.attr('class');
|
var currentClassName = element.attr('class');
|
||||||
var classes = currentClassName + ' ' + className;
|
var classes = currentClassName + ' ' + className;
|
||||||
@@ -700,6 +701,9 @@ angular.module('ngAnimate', ['ng'])
|
|||||||
case 'setClass':
|
case 'setClass':
|
||||||
cancellations.push(animation.fn(element, classNameAdd, classNameRemove, progress, options));
|
cancellations.push(animation.fn(element, classNameAdd, classNameRemove, progress, options));
|
||||||
break;
|
break;
|
||||||
|
case 'animate':
|
||||||
|
cancellations.push(animation.fn(element, className, options.from, options.to, progress));
|
||||||
|
break;
|
||||||
case 'addClass':
|
case 'addClass':
|
||||||
cancellations.push(animation.fn(element, classNameAdd || className, progress, options));
|
cancellations.push(animation.fn(element, classNameAdd || className, progress, options));
|
||||||
break;
|
break;
|
||||||
@@ -819,6 +823,65 @@ angular.module('ngAnimate', ['ng'])
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
return {
|
return {
|
||||||
|
/**
|
||||||
|
* @ngdoc method
|
||||||
|
* @name $animate#animate
|
||||||
|
* @kind function
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Performs an inline animation on the element which applies the provided `to` and `from` CSS styles to the element.
|
||||||
|
* If any detected CSS transition, keyframe or JavaScript matches the provided `className` value then the animation
|
||||||
|
* will take on the provided styles. For example, if a transition animation is set for the given className then the
|
||||||
|
* provided `from` and `to` styles will be applied alongside the given transition. If a JavaScript animation is
|
||||||
|
* detected then the provided styles will be given in as function paramters.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* ngModule.animation('.my-inline-animation', function() {
|
||||||
|
* return {
|
||||||
|
* animate : function(element, className, from, to, done) {
|
||||||
|
* //styles
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Below is a breakdown of each step that occurs during the `animate` animation:
|
||||||
|
*
|
||||||
|
* | Animation Step | What the element class attribute looks like |
|
||||||
|
* |-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------|
|
||||||
|
* | 1. $animate.animate(...) is called | class="my-animation" |
|
||||||
|
* | 2. $animate waits for the next digest to start the animation | class="my-animation ng-animate" |
|
||||||
|
* | 3. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" |
|
||||||
|
* | 4. the className class value is added to the element | class="my-animation ng-animate className" |
|
||||||
|
* | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate className" |
|
||||||
|
* | 6. $animate blocks all CSS transitions on the element to ensure the .className class styling is applied right away| class="my-animation ng-animate className" |
|
||||||
|
* | 7. $animate applies the provided collection of `from` CSS styles to the element | class="my-animation ng-animate className" |
|
||||||
|
* | 8. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate className" |
|
||||||
|
* | 9. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate className" |
|
||||||
|
* | 10. the className-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate className className-active" |
|
||||||
|
* | 11. $animate applies the collection of `to` CSS styles to the element which are then handled by the transition | class="my-animation ng-animate className className-active" |
|
||||||
|
* | 12. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate className className-active" |
|
||||||
|
* | 13. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
||||||
|
* | 14. The returned promise is resolved. | class="my-animation" |
|
||||||
|
*
|
||||||
|
* @param {DOMElement} element the element that will be the focus of the enter animation
|
||||||
|
* @param {object} from a collection of CSS styles that will be applied to the element at the start of the animation
|
||||||
|
* @param {object} to a collection of CSS styles that the element will animate towards
|
||||||
|
* @param {string=} className an optional CSS class that will be added to the element for the duration of the animation (the default class is `ng-inline-animate`)
|
||||||
|
* @param {object=} options an optional collection of options that will be picked up by the CSS transition/animation
|
||||||
|
* @return {Promise} the animation callback promise
|
||||||
|
*/
|
||||||
|
animate : function(element, from, to, className, options) {
|
||||||
|
className = className || 'ng-inline-animate';
|
||||||
|
options = parseAnimateOptions(options) || {};
|
||||||
|
options.from = to ? from : null;
|
||||||
|
options.to = to ? to : from;
|
||||||
|
|
||||||
|
return runAnimationPostDigest(function(done) {
|
||||||
|
return performAnimation('animate', className, stripCommentsFromElement(element), null, null, noop, options, done);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc method
|
* @ngdoc method
|
||||||
* @name $animate#enter
|
* @name $animate#enter
|
||||||
@@ -1256,7 +1319,10 @@ angular.module('ngAnimate', ['ng'])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runner.isClassBased && !runner.isSetClassOperation && !skipAnimation) {
|
if (runner.isClassBased
|
||||||
|
&& !runner.isSetClassOperation
|
||||||
|
&& animationEvent != 'animate'
|
||||||
|
&& !skipAnimation) {
|
||||||
skipAnimation = (animationEvent == 'addClass') == element.hasClass(className); //opposite of XOR
|
skipAnimation = (animationEvent == 'addClass') == element.hasClass(className); //opposite of XOR
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1947,6 +2013,13 @@ angular.module('ngAnimate', ['ng'])
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
animate : function(element, className, from, to, animationCompleted, options) {
|
||||||
|
options = options || {};
|
||||||
|
options.from = from;
|
||||||
|
options.to = to;
|
||||||
|
return animate('animate', element, className, animationCompleted, options);
|
||||||
|
},
|
||||||
|
|
||||||
enter : function(element, animationCompleted, options) {
|
enter : function(element, animationCompleted, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
return animate('enter', element, 'ng-enter', animationCompleted, options);
|
return animate('enter', element, 'ng-enter', animationCompleted, options);
|
||||||
|
|||||||
2
src/ngMock/angular-mocks.js
vendored
2
src/ngMock/angular-mocks.js
vendored
@@ -803,7 +803,7 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
|
|||||||
};
|
};
|
||||||
|
|
||||||
angular.forEach(
|
angular.forEach(
|
||||||
['enter','leave','move','addClass','removeClass','setClass'], function(method) {
|
['animate','enter','leave','move','addClass','removeClass','setClass'], function(method) {
|
||||||
animate[method] = function() {
|
animate[method] = function() {
|
||||||
animate.queue.push({
|
animate.queue.push({
|
||||||
event : method,
|
event : method,
|
||||||
|
|||||||
@@ -50,6 +50,15 @@ describe("$animate", function() {
|
|||||||
expect(element.text()).toBe('21');
|
expect(element.text()).toBe('21');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it("should apply styles instantly to the element",
|
||||||
|
inject(function($animate, $compile, $rootScope) {
|
||||||
|
|
||||||
|
$animate.animate(element, { color: 'rgb(0, 0, 0)' });
|
||||||
|
expect(element.css('color')).toBe('rgb(0, 0, 0)');
|
||||||
|
|
||||||
|
$animate.animate(element, { color: 'rgb(255, 0, 0)' }, { color: 'rgb(0, 255, 0)' });
|
||||||
|
expect(element.css('color')).toBe('rgb(0, 255, 0)');
|
||||||
|
}));
|
||||||
|
|
||||||
it("should still perform DOM operations even if animations are disabled (post-digest)", inject(function($animate, $rootScope) {
|
it("should still perform DOM operations even if animations are disabled (post-digest)", inject(function($animate, $rootScope) {
|
||||||
$animate.enabled(false);
|
$animate.enabled(false);
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ describe("ngAnimate", function() {
|
|||||||
return function($animate, $compile, $rootScope, $rootElement) {
|
return function($animate, $compile, $rootScope, $rootElement) {
|
||||||
element = $compile('<div></div>')($rootScope);
|
element = $compile('<div></div>')($rootScope);
|
||||||
|
|
||||||
forEach(['.ng-hide-add', '.ng-hide-remove', '.ng-enter', '.ng-leave', '.ng-move'], function(selector) {
|
forEach(['.ng-hide-add', '.ng-hide-remove', '.ng-enter', '.ng-leave', '.ng-move', '.my-inline-animation'], function(selector) {
|
||||||
ss.addRule(selector, '-webkit-transition:1s linear all;' +
|
ss.addRule(selector, '-webkit-transition:1s linear all;' +
|
||||||
'transition:1s linear all;');
|
'transition:1s linear all;');
|
||||||
});
|
});
|
||||||
@@ -454,6 +454,20 @@ describe("ngAnimate", function() {
|
|||||||
expect(element.text()).toBe('21');
|
expect(element.text()).toBe('21');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it("should perform the animate event",
|
||||||
|
inject(function($animate, $compile, $rootScope, $timeout, $sniffer) {
|
||||||
|
|
||||||
|
$rootScope.$digest();
|
||||||
|
$animate.animate(element, { color: 'rgb(255, 0, 0)' }, { color: 'rgb(0, 0, 255)' }, 'animated');
|
||||||
|
$rootScope.$digest();
|
||||||
|
|
||||||
|
if($sniffer.transitions) {
|
||||||
|
expect(element.css('color')).toBe('rgb(255, 0, 0)');
|
||||||
|
$animate.triggerReflow();
|
||||||
|
}
|
||||||
|
expect(element.css('color')).toBe('rgb(0, 0, 255)');
|
||||||
|
}));
|
||||||
|
|
||||||
it("should animate the show animation event",
|
it("should animate the show animation event",
|
||||||
inject(function($animate, $rootScope, $sniffer) {
|
inject(function($animate, $rootScope, $sniffer) {
|
||||||
|
|
||||||
@@ -653,6 +667,16 @@ describe("ngAnimate", function() {
|
|||||||
expect(child.attr('class')).toContain('ng-hide-remove-active');
|
expect(child.attr('class')).toContain('ng-hide-remove-active');
|
||||||
browserTrigger(child,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
|
browserTrigger(child,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
|
||||||
|
|
||||||
|
//animate
|
||||||
|
$animate.animate(child, null, null, 'my-inline-animation');
|
||||||
|
$rootScope.$digest();
|
||||||
|
$animate.triggerReflow();
|
||||||
|
|
||||||
|
expect(child.attr('class')).toContain('my-inline-animation');
|
||||||
|
expect(child.attr('class')).toContain('my-inline-animation-active');
|
||||||
|
browserTrigger(child,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
|
||||||
|
$animate.triggerCallbackPromise();
|
||||||
|
|
||||||
//leave
|
//leave
|
||||||
$animate.leave(child);
|
$animate.leave(child);
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
|
|||||||
Reference in New Issue
Block a user