Jquery.animate () ile CSS döndürme çapraz tarayıcı


82

Tarayıcılar arası uyumlu bir rotasyon (ie9 +) oluşturmaya çalışıyorum ve jsfiddle'da aşağıdaki koda sahibim

$(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 ve HTML gerçekten basittir ve sadece demo içindir:

.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>

Döndürme kullanılırken çalışır, .css()ancak kullanılırken çalışmaz .animate(); bu neden ve bunu düzeltmenin bir yolu var mı?

Teşekkürler.


jQuery'nin dönüşü nasıl canlandıracağı hakkında hiçbir fikri yoktur. Belki CSS3 geçişlerini kullanırsınız?
John Dvorak

1
@JanDvorak - IE9'un CSS3 Geçişlerini desteklememesi dışında.
Spudley

1
Ben "düzelt" kısmı için oy vereceğim (sonunda bir stepgeri arama uygulamaya başlayabilirsiniz ), ancak "neden bu" kısmı oldukça açık.
John Dvorak

@Spudley: evet, biliyorum: IE9 desteğinin amacı setInterval kullanmak ve DoRotate işlevini birkaç kez çağırmak olacak.
fransız

BTW - IE'deki CSS Geçişleri için çoklu doldurma olan diğer sorunuza verdiğim cevabımda CSS Zımpara kitaplığına zaten işaret ettim. Denemek isteyebilirsin.
Spudley

Yanıtlar:


223

CSS Dönüşümlerini jQuery ile canlandırmak henüz mümkün değildir. Bunun gibi bir şey yapabilirsiniz:

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

Adım adım geri arama hakkında daha fazla bilgiyi burada bulabilirsiniz: http://api.jquery.com/animate/#step

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

Ve btw: jQuery 1.7+ ile css3 dönüşümlerinin önekini almanıza gerek yok

Güncelleme

Hayatınızı biraz daha kolaylaştırmak için bunu bir jQuery eklentisine sarabilirsiniz:

$.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

Güncelleme2

Ben sırasını yapmak bunu biraz optimize easing, durationve completeönemsiz.

$.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 Güncellemesi

Teşekkür etmek Matteo ile bir sorunu kaydetti kim thisKonuyu tamamlamak içinde şartına callback. Geri aramayı her düğümde ile bağlayarak düzeltildiyse jQuery.proxy.

Sürümü koda Güncelleme 2'den daha önce ekledim .

2.2 Güncellemesi

Dönüşü ileri geri değiştirmek gibi bir şey yapmak istiyorsanız, bu olası bir değişikliktir. İşleve bir başlangıç ​​parametresi ekledim ve bu satırı değiştirdim:

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

Başlama derecesi belirlemek isteyip istemediğine bakılmaksızın, bunu tüm kullanım durumları için nasıl daha genel hale getireceğini bilen biri varsa, lütfen uygun düzenlemeyi yapın.


Kullanım ... oldukça basit!

Esas olarak istenen sonuca ulaşmak için iki yolunuz vardır. Ama ilk önce argümanlara bir göz atalım:

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

"Açı" dışında hepsi isteğe bağlıdır ve varsayılan jQuery.fn.animateözelliklere geri döner:

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

1 inci

Bu yol kısadır, ancak daha fazla argüman aktardıkça biraz belirsiz görünüyor.

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

2.

Üçten fazla argüman varsa nesneleri kullanmayı tercih ederim, bu nedenle bu sözdizimi benim favorim:

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

4
Bunu bir keman yerine koyabilir misin?
frenchie

4
Tamam, çok güzel: bu, tarayıcılar arası (IE9 +) CSS3 döndürme eklentisi !! Bunu iddia edebilirsiniz: bunu siz yaptınız. İyi iş!
fransız

1
@matteo Geç yanıt için özür dilerim ve testiniz için teşekkürler. Sorunu çözmek için biraz zamana ihtiyacım vardı ama hallettim! fiddle.jshell.net/P5J4V/43 Bu arada, araştırmanızdan
cevabımda bahsetmiştim

1
@matteo thisBir DOM nesnesine atıfta bulunmamasının nedeni, bağlamın animate()çağrılan nesneye ayarlanmasıdır , bu durumda {deg: 0}bağlama ayarlanır. Her geri arama işlevinin bağlamını apply()/ call()veya ile $.proxy()(@ yckart'ın gösterdiği gibi) değiştirerek bunu düzeltebilirsiniz . TÜM geri aramaları düzeltmek ve 3d rotasyona izin vermek için benim çözümüm: jsfiddle.net/TrevinAvery/P5J4V/44
Trevin Avery

1
Aynı öğeyi tekrar tekrar canlandırmak istiyorsanız, 0her seferinde derecelerde başlamak beklenen davranışı sağlamaz, bu nedenle mevcut döndürme değeriyle başlatmanız gerekir. Bunun nasıl yapılacağı burada açıklanmaktadır: stackoverflow.com/a/11840120/61818
Asbjørn Ulsberg

17

Teşekkürler yckart! Büyük katkı. Eklentinizi biraz daha detaylandırdım. Tam kontrol ve tarayıcılar arası css için startAngle eklendi.

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

5
jQuery, gerekli satıcı önekini otomatik olarak ekler, böylece buna gerek yoktur!
yckart

Çapraz platform için +1. Harika. @yckart: Bu durumda otomatik ön ek benim için çalışmıyor.
lsmpascal

@PaxMaximinus Hangi jQuery sürümünü kullanıyorsunuz? blog.jquery.com/2012/08/09/jquery-1-8- yayınlandı
yckart

@yckart: 1.7.1 sürümü.
lsmpascal

1
@PaxMaximinus jquery-blog'daki makalede de görebileceğiniz gibi, otomatik ön ek tam da bu yana jquery-1.8+!
yckart

10

jQuery geçişi , jQuery aracılığıyla CSS3 animasyonlarıyla uğraşıyorsanız muhtemelen hayatınızı kolaylaştıracaktır.

DÜZENLEME Mart 2014 (çünkü tavsiyem yayınladığımdan beri sürekli olarak yukarı ve aşağı oylanıyor)

Neden başlangıçta yukarıdaki eklentiye işaret ettiğimi açıklayayım:

DOMHer adımda (yani $.animate) güncellenmesi performans açısından ideal değildir. Çalışır, ancak büyük olasılıkla saf CSS3 geçişlerinden veya CSS3 animasyonlarından daha yavaş olacaktır .

Bunun temel nedeni, geçişin baştan sona nasıl görüneceğini belirtirseniz tarayıcının ileriyi düşünme şansı elde etmesidir.

Bunu yapmak için, örneğin geçişin her durumu için bir CSS sınıfı oluşturabilir ve animasyon durumunu değiştirmek için yalnızca jQuery'yi kullanabilirsiniz.

Bu genellikle oldukça derli topludur, çünkü CSS'nizin geri kalanıyla birlikte animasyonlarınızı işletme mantığınızla karıştırmak yerine değiştirebilirsiniz:

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

Dönüşüm parametrelerinden herhangi biri dinamikse, elbette bunun yerine style niteliğini kullanabilirsiniz:

$('.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'de CSS3 geçişleri hakkında çok daha ayrıntılı bilgi .

ANCAK Akılda tutulması gereken birkaç şey daha var ve karmaşık animasyonlar, zincirleme vb. Varsa tüm bunlar biraz yanıltıcı olabilir ve jQuery Transit kaputun altındaki tüm zorlu bitleri yapar:

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

3

IE7 + dahil bu çapraz tarayıcıyı yapmak için eklentiyi bir dönüşüm matrisiyle genişletmeniz gerekir. Satıcı öneki jQuery'de jquery-1.8 + 'dan yapıldığından, bunu transformmülk için dışarıda bırakacağım .

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

Not: parametreler optionsve startAnglesadece set gerekirse, isteğe bağlıdır startAnglekullanım {}veya nulliçin options.

Örnek kullanım:

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

Demo için bu jsfiddle'a da bakın .

Güncelleme : Artık extra: {}seçenekleri de geçebilirsiniz . Bu, diğer animasyonları aynı anda yürütmenizi sağlayacaktır. Örneğin:

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

Bu, öğeyi 90 derece döndürecek ve 100px ile sağa hareket ettirecek ve animasyon sırasında aynı anda yarı şeffaf hale getirecektir.


Veya IE9, Firefox'ta yapar, ancak yalnızca firefox.
Liam

Tamam, şimdi Chrome, Firefox ve IE10'da çalışıyor. IE9'u test edebilir misin Liam? Sorun, dönüştürme özelliğinin Chrome ve IE için tanımlanmamış olmasıydı, bu nedenle komut dosyası, dönüştürme özelliğinin kullanılamadığını düşünüyordu. Bu nedenle, tüm ön ekleri dahil komut değiştirildi: ms, o, webkit, mozdoğru bir şekilde tespitini sağlamak. Keman da v12'ye güncellenmiştir.
Yeti

2

bu benim çözümüm:

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

sonra bunu varsayılan animate fkt'de kullanabilirsiniz:

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

1

Başka bir cevap, çünkü jQuery.transit, jQuery.easing ile uyumlu değildir. Bu çözüm bir jQuery uzantısı olarak gelir. Daha geneldir, rotasyon özel bir durumdur:

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

Kullanım şu kadar basittir:

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

0

SetInterval ile eklenti çapraz tarayıcı olmadan:

                        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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.