Trình duyệt chéo xoay vòng CSS với jquery.animate ()


81

Tôi đang làm việc để tạo xoay vòng tương thích với nhiều trình duyệt (tức là 9 +) và tôi có mã sau trong 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 và HTML thực sự đơn giản và chỉ dành cho bản demo:

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

Vòng quay hoạt động khi sử dụng .css()nhưng không hoạt động khi sử dụng .animate(); tại sao vậy và có cách nào để khắc phục không?

Cảm ơn.


jQuery không biết cách tạo hoạt ảnh cho vòng quay. Có lẽ sử dụng chuyển tiếp CSS3?
John Dvorak

1
@JanDvorak - ngoại trừ việc IE9 không hỗ trợ CSS3 Transitions.
Spudley

1
Tôi sẽ ủng hộ phần "khắc phục sự cố" (bạn có thể kết thúc việc triển khai stepgọi lại), nhưng phần "tại sao lại như vậy" khá rõ ràng.
John Dvorak

@Spudley: vâng, tôi biết: mục tiêu hỗ trợ IE9 sẽ là sử dụng setInterval và gọi hàm DoRotate nhiều lần.
frenchie

BTW - Tôi đã chỉ ra thư viện Giấy nhám CSS trong câu trả lời của tôi cho câu hỏi khác của bạn, đó là một polyfill cho CSS Transitions trong IE. Bạn có thể muốn thử nó.
Spudley ngày

Câu trả lời:


222

CSS-Transforms vẫn chưa thể tạo hoạt ảnh với jQuery. Bạn có thể làm điều gì đó như sau:

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

Bạn có thể đọc thêm về gọi lại từng bước tại đây: http://api.jquery.com/animate/#step

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

Và, btw: bạn không cần phải chuyển đổi tiền tố css3 với jQuery 1.7+

Cập nhật

Bạn có thể gói nó trong một jQuery-plugin để làm cho cuộc sống của bạn dễ dàng hơn một chút:

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

Cập nhật2

Tôi đã tối ưu hóa nó một chút để tạo thứ tự easing, durationcompletekhông đáng kể.

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

Cập nhật 2.1

Cảm ơn matteo , người đã lưu ý vấn đề với this-context trong bản hoàn chỉnh- callback. Nếu sửa nó bằng cách ràng buộc callback với jQuery.proxymỗi nút.

Tôi đã thêm phiên bản vào mã trước đây từ Bản cập nhật 2 .

Cập nhật 2.2

Đây là một sửa đổi có thể thực hiện nếu bạn muốn làm điều gì đó như chuyển đổi qua lại vòng xoay. Tôi chỉ cần thêm một tham số bắt đầu vào hàm và thay thế dòng này:

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

Nếu có ai biết cách làm cho điều này chung chung hơn cho tất cả các trường hợp sử dụng, cho dù họ có muốn đặt mức độ bắt đầu hay không, vui lòng thực hiện chỉnh sửa thích hợp.


Cách sử dụng ... khá đơn giản!

Chủ yếu bạn có hai cách để đạt được kết quả mong muốn. Nhưng trước tiên, hãy xem xét các đối số:

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

Ngoại trừ "angle", tất cả chúng đều là tùy chọn và dự phòng cho jQuery.fn.animate-properties mặc định :

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

Ngày 1

Cách này là cách ngắn gọn, nhưng có vẻ hơi không rõ ràng khi chúng ta chuyển nhiều đối số hơn.

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

lần 2

Tôi thích sử dụng các đối tượng nếu có nhiều hơn ba đối số, vì vậy cú pháp này là sở thích của tôi:

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

4
Bạn có thể đặt điều này trong một khó khăn?
frenchie

4
Ok, rất tuyệt: đó là plugin CHO xoay vòng CSS3 trên nhiều trình duyệt (IE9 +) !! Bạn có thể khẳng định rằng: bạn đã xây dựng điều đó. Công việc tốt đẹp!
frenchie

1
@matteo Xin lỗi vì phản hồi muộn và cảm ơn bạn đã kiểm tra. Tôi cần một chút thời gian để giải quyết vấn đề, nhưng tôi đã hiểu! fiddle.jshell.net/P5J4V/43 Bằng cách này, tôi đã đề cập điều tra của bạn trong anwer của tôi :)
yckart

1
@matteo Lý do thiskhông tham chiếu đến đối tượng DOM là vì ngữ cảnh được đặt thành đối tượng animate()được gọi vào, trong trường hợp {deg: 0}này được đặt thành ngữ cảnh. Bạn có thể khắc phục điều này bằng cách thay đổi ngữ cảnh của từng hàm gọi lại bằng apply()/ call()hoặc $.proxy()(như @yckart đã hiển thị). Đây là giải pháp của tôi để khắc phục TẤT CẢ các lệnh gọi lại và cho phép xoay 3D: jsfiddle.net/TrevinAvery/P5J4V/44
Trevin Avery

1
Nếu bạn muốn tạo hoạt ảnh nhiều lần cho cùng một phần tử, việc bắt đầu theo 0độ mọi lúc sẽ không dẫn đến hành vi như mong đợi, vì vậy bạn cần khởi tạo với giá trị xoay hiện tại. Làm thế nào để làm điều đó được giải thích ở đây: stackoverflow.com/a/11840120/61818
Asbjørn Ulsberg

17

Cảm ơn yckart! Đóng góp lớn. Tôi đã bổ sung thêm plugin của bạn một chút. Đã thêm startAngle để kiểm soát toàn bộ và css trên nhiều trình duyệt.

$.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 tự động thêm tiền tố nhà cung cấp cần thiết, vì vậy không cần điều này!
yckart

+1 cho nền tảng chéo. Tuyệt quá. @yckart: tiền tố tự động không hoạt động với tôi trong trường hợp này.
lsmpascal

@PaxMaximinus Bạn sử dụng phiên bản jQuery nào? blog.jquery.com/2012/08/09/jquery-1-8-released
yckart

@yckart: phiên bản 1.7.1.
lsmpascal

1
@PaxMaximinus Như bạn có thể thấy trong bài viết từ jquery-blog, tiền tố tự động chỉ có từ đó jquery-1.8+!
yckart

10

Chuyển tiếp jQuery có thể sẽ giúp cuộc sống của bạn dễ dàng hơn nếu bạn đang xử lý các hoạt ảnh CSS3 thông qua jQuery.

CHỈNH SỬA tháng 3 năm 2014 (vì lời khuyên của tôi đã liên tục được bình chọn lên xuống kể từ khi tôi đăng nó)

Hãy để tôi giải thích lý do tại sao ban đầu tôi gợi ý về plugin ở trên:

Cập nhật DOMtrên mỗi bước (tức là $.animate) không phải là lý tưởng về mặt hiệu suất. Nó hoạt động, nhưng hầu hết có thể sẽ chậm hơn so với chuyển tiếp CSS3 thuần túy hoặc hoạt ảnh CSS3 .

Điều này chủ yếu là do trình duyệt có cơ hội suy nghĩ trước nếu bạn cho biết quá trình chuyển đổi sẽ như thế nào từ đầu đến cuối.

Để làm như vậy, bạn có thể ví dụ: tạo một lớp CSS cho mỗi trạng thái của quá trình chuyển đổi và chỉ sử dụng jQuery để chuyển đổi trạng thái hoạt ảnh.

Điều này nhìn chung khá gọn gàng vì bạn có thể chỉnh sửa hoạt ảnh cùng với phần còn lại của CSS thay vì trộn nó với logic kinh doanh của bạn:

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

Nếu bất kỳ thông số biến đổi nào là động, tất nhiên bạn có thể sử dụng thuộc tính style để thay thế:

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

Nhiều thông tin chi tiết hơn về chuyển tiếp CSS3 trên MDN .

TUY NHIÊN Có một số điều khác cần lưu ý và tất cả những điều này có thể hơi phức tạp nếu bạn có các hoạt ảnh phức tạp, chuỗi, v.v. và jQuery Transit chỉ thực hiện tất cả các phần phức tạp dưới mui xe:

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

3

Để thực hiện điều này trên nhiều trình duyệt bao gồm IE7 +, bạn sẽ cần mở rộng plugin bằng ma trận chuyển đổi. Vì tiền tố của nhà cung cấp được thực hiện trong jQuery từ jquery-1.8 + nên tôi sẽ loại bỏ điều đó cho thuộc transformtính.

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

Lưu ý: Các tham số optionsstartAnglelà tùy chọn, nếu bạn chỉ cần đặt startAnglesử dụng {}hoặc nullcho options.

Ví dụ sử dụng:

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

Xem thêm jsfiddle này để có bản demo.

Cập nhật : Bây giờ bạn cũng có thể vượt qua extra: {}các tùy chọn. Điều này sẽ giúp bạn có thể thực hiện đồng thời các hoạt ảnh khác. Ví dụ:

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

Thao tác này sẽ xoay phần tử 90 độ và di chuyển phần tử đó sang bên phải với 100px và đồng thời làm cho phần tử bán trong suốt trong suốt hoạt ảnh.


Hoặc IE9, có trong Firefox, nhưng chỉ firefox.
Liam

Được rồi, bây giờ nó hoạt động trên Chrome, Firefox và IE10. Bạn có thể kiểm tra IE9, Liam? Vấn đề là thuộc tính chuyển đổi không được xác định cho Chrome và IE, do đó, tập lệnh cho rằng thuộc tính biến đổi không khả dụng. Do đó, tôi đã thay đổi kịch bản để bao gồm tất cả các tiền tố: ms, o, webkit, mozđể đảm bảo phát hiện một cách chính xác. Fiddle cũng được cập nhật lên v12.
Yeti

2

đây là giải pháp của tôi:

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

thì bạn có thể sử dụng nó trong fkt hoạt ảnh mặc định:

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

Một câu trả lời khác, vì jQuery.transit không tương thích với jQuery.easing. Giải pháp này là một phần mở rộng của jQuery. Chung chung hơn, xoay vòng là một trường hợp cụ thể:

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

Cách sử dụng rất đơn giản như:

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

0

Không có trình duyệt chéo plugin với 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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.