用jquery.animate()交叉浏览CSS
我正在创build一个跨浏览器兼容的旋转(ie9 +),我有一个jsfiddle下面的代码
$(document).ready(function () { DoRotate(30); AnimateRotate(30); }); function DoRotate(d) { $("#MyDiv1").css({ '-moz-transform':'rotate('+d+'deg)', '-webkit-transform':'rotate('+d+'deg)', '-o-transform':'rotate('+d+'deg)', '-ms-transform':'rotate('+d+'deg)', 'transform': 'rotate('+d+'deg)' }); } function AnimateRotate(d) { $("#MyDiv2").animate({ '-moz-transform':'rotate('+d+'deg)', '-webkit-transform':'rotate('+d+'deg)', '-o-transform':'rotate('+d+'deg)', '-ms-transform':'rotate('+d+'deg)', 'transform':'rotate('+d+'deg)' }, 1000); }
CSS和HTML非常简单,只是为了演示:
.SomeDiv{ width:50px; height:50px; margin:50px 50px; background-color: red;} <div id="MyDiv1" class="SomeDiv">test</div> <div id="MyDiv2" class="SomeDiv">test</div>
使用.css()
时旋转工作,但在使用.animate()
时.animate()
。 为什么是这样的,有没有办法解决它?
谢谢。
jQuery的CSS转换是不可能的animation。 你可以做这样的事情:
function AnimateRotate(angle) { // caching the object for performance reasons var $elem = $('#MyDiv2'); // we use a pseudo object for the animation // (starts from `0` to `angle`), you can name it as you want $({deg: 0}).animate({deg: angle}, { duration: 2000, step: function(now) { // in the step-callback (that is fired each step of the animation), // you can use the `now` paramter which contains the current // animation-position (`0` up to `angle`) $elem.css({ transform: 'rotate(' + now + 'deg)' }); } }); }
你可以在这里阅读更多关于step-callback: http : //api.jquery.com/animate/#step
而且,顺便说一句:你不需要用jQuery 1.7+前缀css3转换
更新
你可以把它包装在一个jQuery插件中,让你的生活更轻松一些:
$.fn.animateRotate = function(angle, duration, easing, complete) { return this.each(function() { var $elem = $(this); $({deg: 0}).animate({deg: angle}, { duration: duration, easing: easing, step: function(now) { $elem.css({ transform: 'rotate(' + now + 'deg)' }); }, complete: complete || $.noop }); }); }; $('#MyDiv2').animateRotate(90);
http://jsbin.com/ofagog/2/edit
UPDATE2
我对它进行了一些优化,使得easing
, duration
和complete
无关紧要。
$.fn.animateRotate = function(angle, duration, easing, complete) { var args = $.speed(duration, easing, complete); var step = args.step; return this.each(function(i, e) { args.complete = $.proxy(args.complete, e); args.step = function(now) { $.style(e, 'transform', 'rotate(' + now + 'deg)'); if (step) return step.apply(e, arguments); }; $({deg: 0}).animate({deg: angle}, args); }); };
更新2.1
感谢matteo在完整callback
提到了这个问题。 如果通过在每个节点上使用jQuery.proxy
绑定callback来修复它。
从Update 2开始,我已经将版本添加到了代码中。
用法…很简单!
主要有两种方法来达到预期的结果。 但是,首先我们来看看这些论点:
jQuery.fn.animateRotate(angle, duration, easing, complete)
除了“angular度”都是可选的,并回jQuery.fn.animate
默认的jQuery.fn.animate
-properties:
duration: 400 easing: "swing" complete: function () {}
1
这种方式是短的,但看起来有点不清楚,我们通过更多的论据。
$(node).animateRotate(90); $(node).animateRotate(90, function () {}); $(node).animateRotate(90, 1337, 'linear', function () {});
第2
如果有三个以上的参数,我更喜欢使用对象,所以这个语法是我最喜欢的:
$(node).animateRotate(90, { duration: 1337, easing: 'linear', complete: function () {}, step: function () {} });
谢谢你! 伟大的贡献。 我更充实了你的插件。 完全控制和跨浏览器的CSS添加startAngle。
$.fn.animateRotate = function(startAngle, endAngle, duration, easing, complete){ return this.each(function(){ var elem = $(this); $({deg: startAngle}).animate({deg: endAngle}, { duration: duration, easing: easing, step: function(now){ elem.css({ '-moz-transform':'rotate('+now+'deg)', '-webkit-transform':'rotate('+now+'deg)', '-o-transform':'rotate('+now+'deg)', '-ms-transform':'rotate('+now+'deg)', 'transform':'rotate('+now+'deg)' }); }, complete: complete || $.noop }); }); };
如果你正在通过jQuery处理CSS3animation,jQuery转换可能会让你的生活更轻松。
编辑2014年3月 (因为我的意见不断地上下投票,因为我发布)
让我解释为什么我最初暗示上面的插件:
在每个步骤更新DOM
(即$.animate
)在性能方面都不理想。 它的工作原理,但最有可能比纯CSS3转换或CSS3animation慢。
这主要是因为如果您指出从开始到结束的转换过程,浏览器就有机会提前思考。
为此,您可以为每个转换状态创build一个CSS类,并只使用jQuery切换animation状态。
这通常是相当整洁的,因为你可以调整你的CSSanimation,而不是将其与你的业务逻辑混合起来:
// initial state .eye { -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); transform: rotate(45deg); // etc. // transition settings -webkit-transition: -webkit-transform 1s linear 0.2s; -moz-transition: -moz-transform 1s linear 0.2s; transition: transform 1s linear 0.2s; // etc. } // open state .eye.open { transform: rotate(90deg); } // Javascript $('.eye').on('click', function () { $(this).addClass('open'); });
如果任何转换参数是dynamic的,你当然可以使用style属性来代替:
$('.eye').on('click', function () { $(this).css({ -webkit-transition: '-webkit-transform 1s ease-in', -moz-transition: '-moz-transform 1s ease-in', // ... // note that jQuery will vendor prefix the transform property automatically transform: 'rotate(' + (Math.random()*45+45).toFixed(3) + 'deg)' }); });
有关MDN上CSS3转换的更多详细信息。
但是还有其他一些事情要记住,如果你有复杂的animation,链接等等,所有这些都会变得棘手。而jQuery Transit只是把所有棘手的问题都搞清楚了:
$('.eye').transit({ rotate: '90deg'}); // easy huh ?
为了跨浏览器,包括IE7 +,你需要用一个转换matrix来扩展插件。 由于供应商前缀是从jquery-1.8 +在jQuery中完成的,我将把它留给transform
属性。
$.fn.animateRotate = function(endAngle, options, startAngle) { return this.each(function() { var elem = $(this), rad, costheta, sintheta, matrixValues, noTransform = !('transform' in this.style || 'webkitTransform' in this.style || 'msTransform' in this.style || 'mozTransform' in this.style || 'oTransform' in this.style), anims = {}, animsEnd = {}; if(typeof options !== 'object') { options = {}; } else if(typeof options.extra === 'object') { anims = options.extra; animsEnd = options.extra; } anims.deg = startAngle; animsEnd.deg = endAngle; options.step = function(now, fx) { if(fx.prop === 'deg') { if(noTransform) { rad = now * (Math.PI * 2 / 360); costheta = Math.cos(rad); sintheta = Math.sin(rad); matrixValues = 'M11=' + costheta + ', M12=-'+ sintheta +', M21='+ sintheta +', M22='+ costheta; $('body').append('Test ' + matrixValues + '<br />'); elem.css({ 'filter': 'progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\'auto expand\','+matrixValues+')', '-ms-filter': 'progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\'auto expand\','+matrixValues+')' }); } else { elem.css({ //webkitTransform: 'rotate('+now+'deg)', //mozTransform: 'rotate('+now+'deg)', //msTransform: 'rotate('+now+'deg)', //oTransform: 'rotate('+now+'deg)', transform: 'rotate('+now+'deg)' }); } } }; if(startAngle) { $(anims).animate(animsEnd, options); } else { elem.animate(animsEnd, options); } }); };
注:参数options
和startAngle
是可选的,如果您只需要设置startAngle
使用{}
或null
。
用法示例:
var obj = $(document.createElement('div')); obj.on("click", function(){ obj.stop().animateRotate(180, { duration: 250, complete: function() { obj.animateRotate(0, { duration: 250 }); } }); }); obj.text('Click me!'); obj.css({cursor: 'pointer', position: 'absolute'}); $('body').append(obj);
另请参阅此jsfiddle进行演示。
更新 :您现在也可以在选项中传递extra: {}
。 这将使您能够同时执行其他animation。 例如:
obj.animateRotate(90, {extra: {marginLeft: '100px', opacity: 0.5}});
这会将元素旋转90度,并将其向右移动100px,并在animation期间同时使其变为半透明。
这是我的解决scheme:
var matrixRegex = /(?:matrix\(|\s*,\s*)([-+]?[0-9]*\.?[0-9]+(?:[e][-+]?[0-9]+)?)/gi; var getMatches = function(string, regex) { regex || (regex = matrixRegex); var matches = []; var match; while (match = regex.exec(string)) { matches.push(match[1]); } return matches; }; $.cssHooks['rotation'] = { get: function(elem) { var $elem = $(elem); var matrix = getMatches($elem.css('transform')); if (matrix.length != 6) { return 0; } return Math.atan2(parseFloat(matrix[1]), parseFloat(matrix[0])) * (180/Math.PI); }, set: function(elem, val){ var $elem = $(elem); var deg = parseFloat(val); if (!isNaN(deg)) { $elem.css({ transform: 'rotate(' + deg + 'deg)' }); } } }; $.cssNumber.rotation = true; $.fx.step.rotation = function(fx) { $.cssHooks.rotation.set(fx.elem, fx.now + fx.unit); };
那么你可以在默认的animationfkt中使用它:
//rotate to 90 deg cw $('selector').animate({ rotation: 90 }); //rotate to -90 deg ccw $('selector').animate({ rotation: -90 }); //rotate 90 deg cw from current rotation $('selector').animate({ rotation: '+=90' }); //rotate 90 deg ccw from current rotation $('selector').animate({ rotation: '-=90' });
另一个答案,因为jQuery.transit与jQuery.easing不兼容。 这个解决scheme是作为一个jQuery扩展。 更通用的,轮换是一个特定的情况:
$.fn.extend({ animateStep: function(options) { return this.each(function() { var elementOptions = $.extend({}, options, {step: options.step.bind($(this))}); $({x: options.from}).animate({x: options.to}, elementOptions); }); }, rotate: function(value) { return this.css("transform", "rotate(" + value + "deg)"); } });
用法很简单:
$(element).animateStep({from: 0, to: 90, step: $.fn.rotate});
没有插件与setInterval跨浏览器:
function rotatePic() { jQuery({deg: 0}).animate( {deg: 360}, {duration: 3000, easing : 'linear', step: function(now, fx){ jQuery("#id").css({ '-moz-transform':'rotate('+now+'deg)', '-webkit-transform':'rotate('+now+'deg)', '-o-transform':'rotate('+now+'deg)', '-ms-transform':'rotate('+now+'deg)', 'transform':'rotate('+now+'deg)' }); } }); } var sec = 3; rotatePic(); var timerInterval = setInterval(function() { rotatePic(); sec+=3; if (sec > 30) { clearInterval(timerInterval); } }, 3000);