CSS вращение кросс-браузер с jquery.живой()



Я работаю над созданием кросс-браузерной совместимой ротации (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(). почему это происходит и есть ли способ это исправить?



спасибо.

552   7  

7 ответов:

CSS-преобразования пока невозможно анимировать с помощью 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)'
            });
        }
    });
}

вы можете прочитать больше о step-callback здесь:http://api.jquery.com/animate/#step

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

и, кстати: вам не нужно префикс CSS3 преобразования с jQuery 1.7+

обновление

вы можете обернуть это в 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

обновление 2

я оптимизировал его немного, чтобы сделать заказ 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

спасибо Маттео кто заметил проблему с this-контекст, в полной-callback. Если это исправлено обязательные обратный вызов с jQuery.proxy на каждый узел.

у меня есть добавлено издание в код ранее от обновление 2.

обновление 2.2

это возможные модификации, Если вы хотите сделать что-то вроде переключения вращения вперед и назад. Я просто добавил параметр start в функцию и заменил эту строку:

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

если кто-нибудь знает, как сделать это более общим для всех случаев использования, независимо от того, хотят ли они установить начальную степень, пожалуйста, сделайте соответствующий редактировать.


использование...довольно просто!

в основном у вас есть два способа достичь желаемого результата. Но сначала давайте посмотрим на аргументы:

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

за исключением "угла", все они являются необязательными и резервными по умолчанию jQuery.fn.animateсвойства:

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

спасибо yckart! Значительный вклад. Я конкретизировал ваш плагин немного больше. Добавлена startAngle для полного контроля и кросс-браузер css.

$.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 transit вероятно, сделает вашу жизнь проще, если вы имеете дело с анимацией CSS3 через jQuery.

редактировать март 2014 (потому что мой совет постоянно был вверх и вниз проголосовали, так как я разместил его)

позвольте мне объяснить, почему я изначально намекал на плагин выше:

обновление DOM на каждом шаге (т. е. $.animate ) не является идеальным с точки зрения производительности. Оно работает, но, скорее всего, будет медленнее, чем чистый CSS3 переходы или CSS3 анимации.

это в основном потому, что браузер получает возможность думать вперед, если вы укажете, как будет выглядеть переход от начала до конца.

для этого можно, например, создать класс CSS для каждого состояния перехода и использовать только jQuery для переключения состояния анимации.

это, как правило, довольно аккуратно, как вы можете настроить вас анимация вместе с остальной частью вашего 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'); });

если какой-либо из параметров преобразования является динамическим, вы можете, конечно, использовать атрибут 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)'
    }); 
});

гораздо более подробная информация о CSS3 переходы на MDN.

есть несколько других вещей, чтобы держать в уме и все это может получить немного сложнее, если у вас есть сложные анимации, цепочки и т. д. и jQuery Transit просто не все хитрые биты под капотом:

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

для этого кросс-браузер в том числе IE7+, вам нужно будет расширить плагин с матрицей преобразования. Поскольку префикс поставщика выполняется в jQuery из jquery-1.8+, я оставлю это для 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 на options.

пример использования:

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 для a демонстрация.

обновление: теперь вы можете также пройти extra: {} в параметрах. Это позволит вам выполнять другие анимации одновременно. Например:

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

это повернет элемент на 90 градусов и переместит его вправо с помощью 100px и сделает его полупрозрачным одновременно во время анимации.

Это мое решение:

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

затем вы можете использовать его в анимированном 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' });

другой ответ, потому что jQuery.транзит не совместим с jQuery.ослабление. Это решение поставляется в виде расширения 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);

Comments

    Ничего не найдено.