所以我一直在开发一个基于CSS过渡的轻量级插件。它能够动态地添加内联样式(过渡)。
插件代码的某些部分(如前缀CSS属性)被删除,使事情更清楚:
(function($, window, document) {
'use strict';
var plugin = 'transition';
// Constructors
function Transition(element, animation, options) {
this.element = element;
this.animation = animation;
this.direction = null;
this.settings = $.extend({}, $.fn[plugin].defaults, options);
this.init();
}
// Instance
$.extend(Transition.prototype, {
init: function() {
var instance = this;
instance.direction = $(instance.element).is(':visible') ? // toggle
'outward':
'inward' ;
setTimeout(function() { // separate queue entry to make sure previous re-draw events are finished
instance.settings.animations.hasOwnProperty(instance.animation) ?
instance.start():
console.error('Trying to call an undefined animation');
}, 0);
},
/**
* Start the transition.
*/
start: function() {
var instance = this,
$element = $(instance.element);
// Bind handlers
$element
.one('transitionstart', function() {
instance.settings.onStart.call($element);
})
.one('transitionend', function() {
instance.end();
});
// Add inline styles
$element
.css(instance.style('start'))
.show() // ensure the element is visible
.css(instance.style('end'));
},
/**
* End the transition.
*/
end: function() {
var instance = this,
$element = $(instance.element);
instance.direction == 'inward' ?
$element.show():
$element.hide();
instance.settings.onEnd.call($element);
$element.css({
opacity: '',
transform: '',
transformOrigin: '',
transition: ''
}).dequeue();
},
/**
* Get the inline style for the transition.
*
* @param state
*/
style: function(state) {
var instance = this,
animation = instance.settings.animations[instance.animation],
direction = instance.direction,
css = {};
if (state === 'start') {
css = (direction == 'inward') ?
animation.start:
animation.end; // reversed
css['transition'] = 'all ' +
instance.settings.duration + 'ms ' +
instance.settings.curve + ' ' +
instance.settings.delay + 'ms';
} else {
css = (direction == 'inward') ?
animation.end:
animation.start; // reversed
}
return css;
}
});
// Plugin definition
$.fn[plugin] = function(animation, options) {
return this.each(function() {
$(this).queue(function() {
new Transition(this, animation, options);
});
});
};
// Default settings
$.fn[plugin].defaults = {
duration : 500,
delay : 0,
curve : 'ease',
onStart : function() {},
onEnd : function() {}
};
$.fn[plugin].defaults.animations = {
fade: {
start : { 'opacity': 0 },
end : { 'opacity': 1 }
},
scale: {
start : { 'opacity': 0, 'transform': 'scale(0.8)' },
end : { 'opacity': 1, 'transform': 'scale(1.0)' }
},
slide: {
start : { 'opacity': 0, 'transform': 'scaleY(0)', 'transform-origin': 'bottom'},
end : { 'opacity': 1, 'transform': 'scaleY(1)', 'transform-origin': 'bottom'}
}
};
})(jQuery, window, document);
$('#fading').transition('fade', {duration: 1000, delay: 1000});
$('#scaling').transition('scale', {duration: 1000, delay: 1000});
$('#sliding').transition('slide', {duration: 1000, delay: 1000});
div {
display: inline-block;
margin-bottom: 1em;
padding: 3em 2em;
background-color: #EEE;
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="fading">Fading block</div>
<div id="scaling">Scaling block</div>
<div id="sliding">Sliding block</div>
由于某些原因,滑动动画在Chrome上不起作用,元素只是淡入/淡出。FireFox和Edge没有这个问题。
应用于滑动动画的CSS:
slide: {
start : { 'opacity': 0, 'transform': 'scaleY(0)', 'transform-origin': 'bottom'},
end : { 'opacity': 1, 'transform': 'scaleY(1)', 'transform-origin': 'bottom'}
}
希望任何魔术师都能弄清楚这是怎么回事。
这是一个已知的转换比例(0)的bug。只需将其更改为缩放(0.01)。
(function($, window, document) {
'use strict';
var plugin = 'transition';
// Constructors
function Transition(element, animation, options) {
this.element = element;
this.animation = animation;
this.direction = null;
this.settings = $.extend({}, $.fn[plugin].defaults, options);
this.init();
}
// Instance
$.extend(Transition.prototype, {
init: function() {
var instance = this;
instance.direction = $(instance.element).is(':visible') ? // toggle
'outward' :
'inward';
setTimeout(function() { // separate queue entry to make sure previous re-draw events are finished
instance.settings.animations.hasOwnProperty(instance.animation) ?
instance.start() :
console.error('Trying to call an undefined animation');
}, 0);
},
/**
* Start the transition.
*/
start: function() {
var instance = this,
$element = $(instance.element);
// Bind handlers
$element
.one('transitionstart', function() {
instance.settings.onStart.call($element);
})
.one('transitionend', function() {
instance.end();
});
// Add inline styles
$element
.css(instance.style('start'))
.show() // ensure the element is visible
.css(instance.style('end'));
},
/**
* End the transition.
*/
end: function() {
var instance = this,
$element = $(instance.element);
instance.direction == 'inward' ?
$element.show() :
$element.hide();
instance.settings.onEnd.call($element);
$element.css({
opacity: '',
transform: '',
transformOrigin: '',
transition: ''
}).dequeue();
},
/**
* Get the inline style for the transition.
*
* @param state
*/
style: function(state) {
var instance = this,
animation = instance.settings.animations[instance.animation],
direction = instance.direction,
css = {};
if (state === 'start') {
css = (direction == 'inward') ?
animation.start :
animation.end; // reversed
css['transition'] = 'all ' +
instance.settings.duration + 'ms ' +
instance.settings.curve + ' ' +
instance.settings.delay + 'ms';
} else {
css = (direction == 'inward') ?
animation.end :
animation.start; // reversed
}
return css;
}
});
// Plugin definition
$.fn[plugin] = function(animation, options) {
return this.each(function() {
$(this).queue(function() {
new Transition(this, animation, options);
});
});
};
// Default settings
$.fn[plugin].defaults = {
duration: 500,
delay: 0,
curve: 'ease',
onStart: function() {},
onEnd: function() {}
};
$.fn[plugin].defaults.animations = {
fade: {
start: {
'opacity': 0
},
end: {
'opacity': 1
}
},
scale: {
start: {
'opacity': 0,
'transform': 'scale(0.8)'
},
end: {
'opacity': 1,
'transform': 'scale(1.0)'
}
},
slide: {
start: {
'opacity': 0.5,
'transform': 'scaleY(0.01)',
'transform-origin': 'bottom'
},
end: {
'opacity': 1,
'transform': 'scaleY(1)',
'transform-origin': 'bottom'
}
}
};
})(jQuery, window, document);
$('#fading').transition('fade', {
duration: 1000,
delay: 1000
});
$('#scaling').transition('scale', {
duration: 1000,
delay: 1000
});
$('#sliding').transition('slide', {
duration: 1000,
delay: 1000
});
div {
display: inline-block;
margin-bottom: 1em;
padding: 3em 2em;
background-color: #EEE;
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="fading">Fading block</div>
<div id="scaling">Scaling block</div>
<div id="sliding">Sliding block</div>