带有 jquery.animate() 的 CSS 旋转跨浏览器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15191058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 14:34:32  来源:igfitidea点击:

CSS rotation cross browser with jquery.animate()

jquerycssrotationjquery-animate

提问by frenchie

I'm working on creating a cross-browser compatible rotation (ie9+) and I have the following code in a jsfiddle

我正在创建一个跨浏览器兼容的旋转(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); 
}

The CSS and HTML are really simple and just for demo:

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>

The rotation works when using .css()but not when using .animate(); why is that and is there a way to fix it?

使用时旋转有效,.css()但使用时无效.animate();为什么会这样,有没有办法解决它?

Thanks.

谢谢。

回答by yckart

CSS-Transforms are not possible to animate with jQuery, yet. You can do something like this:

CSS-Transforms 还不能用 jQuery 制作动画。你可以这样做:

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)'
            });
        }
    });
}

You can read more about the step-callback here: http://api.jquery.com/animate/#step

您可以在此处阅读有关 step-callback 的更多信息:http: //api.jquery.com/animate/#step

http://jsfiddle.net/UB2XR/23/

http://jsfiddle.net/UB2XR/23/

And, btw: you don't need to prefix css3 transforms with jQuery 1.7+

而且,顺便说一句:您不需要使用 jQuery 1.7+ 为 css3 转换添加前缀

Update

更新

You can wrap this in a jQuery-plugin to make your life a bit easier:

你可以把它包装在一个 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

http://jsbin.com/ofagog/2/edit

Update2

更新2

I optimized it a bit to make the order of easing, durationand completeinsignificant.

我优化了一点,使的顺序easingdurationcomplete微不足道。

$.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);
  });
};

Update 2.1

更新 2.1

Thanks to matteowho noted an issue with the this-context in the complete-callback. If fixed it by bindingthe callback with jQuery.proxyon each node.

感谢matteo,他指出了thiscomplete- 中 -context的问题callback。如果通过在每个节点上绑定回调来修复它jQuery.proxy

I've added the edition to the code before from Update 2.

我之前从Update 2将版本添加到代码中。

Update 2.2

更新 2.2

This is a possible modification if you want to do something like toggle the rotation back and forth. I simply added a start parameter to the function and replaced this line:

如果您想执行诸如来回切换旋转之类的操作,这是一种可能的修改。我只是在函数中添加了一个 start 参数并替换了这一行:

$({deg: start}).animate({deg: angle}, args);

If anyone knows how to make this more generic for all use cases, whether or not they want to set a start degree, please make the appropriate edit.

如果有人知道如何使所有用例更通用,无论他们是否要设置起始度,请进行适当的编辑。



The Usage...is quite simple!

用法……很简单!

Mainly you've two ways to reach the desired result. But at the first, let's take a look on the arguments:

主要有两种方法可以达到预期的结果。但首先,让我们来看看论点:

jQuery.fn.animateRotate(angle, duration, easing, complete)

jQuery.fn.animateRotate(angle, duration, easing, complete)

Except of "angle" are all of them optional and fallback to the default jQuery.fn.animate-properties:

除了“角度”之外,它们都是可选的,并回jQuery.fn.animate退到默认的-properties:

duration: 400
easing: "swing"
complete: function () {}

1st

第一

This way is the short one, but looks a bit unclear the more arguments we pass in.

这种方式很短,但我们传入的参数越多,看起来就越不清楚。

$(node).animateRotate(90);
$(node).animateRotate(90, function () {});
$(node).animateRotate(90, 1337, 'linear', function () {});

2nd

第二

I prefer to use objects if there are more than three arguments, so this syntax is my favorit:

如果参数超过三个,我更喜欢使用对象,所以我最喜欢这个语法:

$(node).animateRotate(90, {
  duration: 1337,
  easing: 'linear',
  complete: function () {},
  step: function () {}
});

回答by drabname

Thanks yckart! Great contribution. I fleshed out your plugin a bit more. Added startAngle for full control and cross-browser css.

谢谢yckart!伟大的贡献。我充实了你的插件。为完全控制和跨浏览器 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
        });
    });
};

回答by Theo.T

jQuery transitwill probably make your life easier if you are dealing with CSS3 animations through jQuery.

如果您通过 jQuery 处理 CSS3 动画,jQuery 传输可能会让您的生活更轻松。

EDIT March 2014(because my advice has constantly been up and down voted since I posted it)

编辑 2014 年 3 月(因为我的建议自发布以来一直被上下投票)

Let me explain why I was initially hinting towards the plugin above:

让我解释一下为什么我最初暗示上面的插件:

Updating the DOMon each step (i.e. $.animate) is not ideal in terms of performance. It works, but will most probably be slower than pure CSS3 transitionsor CSS3 animations.

就性能而言,更新DOM每个步骤 (即$.animate) 并不理想。它有效,但很可能比纯CSS3 过渡CSS3 动画慢。

This is mainly because the browser gets a chance to think ahead if you indicate what the transition is going to look like from start to end.

这主要是因为如果您指出从开始到结束的过渡将是什么样子,浏览器就有机会提前思考。

To do so, you can for example create a CSS class for each state of the transition and only use jQuery to toggle the animation state.

为此,您可以例如为过渡的每个状态创建一个 CSS 类,并且仅使用 jQuery 来切换动画状态。

This is generally quite neat as you can tweak you animations alongside the rest of your CSS instead of mixing it up with your business logic:

这通常非常简洁,因为您可以与 CSS 的其余部分一起调整动画,而不是将其与您的业务逻辑混在一起:

// 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'); });

If any of the transform parameters is dynamic you can of course use the style attribute instead:

如果任何转换参数是动态的,您当然可以改用 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)'
    }); 
});

A lot more detailed information on CSS3 transitions on MDN.

关于 MDNCSS3 转换的更多详细信息。

HOWEVERThere are a few other things to keep in mind and all this can get a bit tricky if you have complex animations, chaining etc. and jQuery Transitjust does all the tricky bits under the hood:

然而,还有一些其他的事情需要记住,如果你有复杂的动画、链接等,所有这些都会变得有点棘手,而jQuery Transit只是在引擎盖下完成所有棘手的部分:

$('.eye').transit({ rotate: '90deg'}); // easy huh ?

回答by Yeti

To do this cross browser including IE7+, you will need to expand the plugin with a transformation matrix. Since vendor prefix is done in jQuery from jquery-1.8+ I will leave that out for the transformproperty.

要在包括 IE7+ 在内的跨浏览器中执行此操作,您需要使用转换矩阵扩展插件。由于供应商前缀是在 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);
        }
    });
};

Note: The parameters optionsand startAngleare optional, if you only need to set startAngleuse {}or nullfor options.

注意:参数optionsstartAngle是可选的,如果您只需要设置startAngleuse{}nullfor options

Example usage:

用法示例:

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);

See also this jsfiddlefor a demo.

另请参阅此jsfiddle以获取演示。

Update: You can now also pass extra: {}in the options. This will make you able to execute other animations simultaneously. For example:

更新:您现在还可以传入extra: {}选项。这将使您能够同时执行其他动画。例如:

obj.animateRotate(90, {extra: {marginLeft: '100px', opacity: 0.5}});

This will rotate the element 90 degrees, and move it to the right with 100px and make it semi-transparent all at the same time during the animation.

这会将元素旋转 90 度,并将其向右移动 100 像素,并在动画过程中同时使其半透明。

回答by AntiCampeR

this is my solution:

这是我的解决方案:

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);
};

then you can use it in the default animate fkt:

然后你可以在默认的 animate fkt 中使用它:

//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' });

回答by Tires

Another answer, because jQuery.transit is not compatible with jQuery.easing. This solution comes as an jQuery extension. Is more generic, rotation is a specific case:

另一个答案,因为 jQuery.transit 与 jQuery.easing 不兼容。这个解决方案是一个 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)");
    }
});

The usage is as simple as:

用法很简单:

$(element).animateStep({from: 0, to: 90, step: $.fn.rotate});

回答by Alexey Alexeenka

Without plugin cross browser with setInterval:

没有带 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);