Callback của .animate () được gọi hai lần jquery


103

Vì tôi đã thêm một số scrollTop-animation, một số phần của lệnh gọi lại của tôi được gọi hai lần:

$('html, body').animate({scrollTop: '0px'}, 300,function() {
    $('#content').load(window.location.href, postdata, function() {                 
        $('#step2').addClass('stepactive').hide().fadeIn(700, function() {
            $('#content').show('slide',800);                    
        });
    });
});

Nó dường như chỉ lặp lại .show(), ít nhất tôi không có ấn tượng rằng cái load()hoặc cái .fadeIn()được gọi là lần thứ hai. Việc này .show()được lặp lại ngay sau khi nó kết thúc lần đầu tiên. Nhân tiện, đặt tốc độ hoạt ảnh scrollTop thành 0không hữu ích!

Tôi cho rằng nó có liên quan gì đó đến hàng đợi hoạt ảnh, nhưng tôi không thể tìm ra cách tìm giải pháp thay thế và đặc biệt là tại sao điều này lại xảy ra.

Câu trả lời:


162

animategọi lại nó một lần cho mỗi phần tử trong tập hợp bạn gọi animate:

Nếu cung cấp, start, step, progress, complete, done, fail, và alwayscallbacks được gọi là trên một cơ sở cho mỗi yếu tố ...

Vì bạn đang tạo hoạt ảnh cho hai phần tử ( htmlphần tử và bodyphần tử), bạn sẽ nhận được hai lần gọi lại. (Đối với bất kỳ ai thắc mắc tại sao OP lại tạo hoạt ảnh cho hai phần tử, đó là vì hoạt ảnh hoạt động bodytrên một số trình duyệt nhưng htmltrên các trình duyệt khác.)

Để nhận được một lệnh gọi lại duy nhất khi hoạt ảnh hoàn tất, animatetài liệu hướng bạn đến bằng cách sử dụng promisephương thức để nhận lời hứa cho hàng đợi hoạt ảnh, sau đó sử dụng thenđể xếp hàng gọi lại:

$("html, body").animate(/*...*/)
    .promise().then(function() {
        // Animation complete
    });

(Lưu ý: Kevin B đã chỉ ra điều này trong câu trả lời của anh ấy khi câu hỏi được đặt ra lần đầu tiên. Tôi cho đến bốn năm sau khi nhận thấy câu trả lời bị thiếu, đã thêm nó và ... sau đó xem câu trả lời của Kevin. Vui lòng cho câu trả lời của anh ấy yêu nó xứng đáng. Tôi đã nghĩ rằng đây là câu trả lời được chấp nhận, tôi nên để nó trong.)

Dưới đây là một ví dụ hiển thị cả lệnh gọi lại phần tử riêng lẻ và lệnh gọi lại hoàn thành tổng thể:

jQuery(function($) {

  $("#one, #two").animate({
    marginLeft: "30em"
  }, function() {
    // Called per element
    display("Done animating " + this.id);
  }).promise().then(function() {
    // Called when the animation in total is complete
    display("Done with animation");
  });

  function display(msg) {
    $("<p>").html(msg).appendTo(document.body);
  }
});
<div id="one">I'm one</div>
<div id="two">I'm two</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>


2
Vâng, đó là lý do và thực sự tôi không thể nhớ lại tại sao tôi đã từng viết html, body. Đã đến lúc tôi bật não trở lại. Cảm ơn
Anonymous

21
Có thể là vì chỉ tạo hoạt ảnh html sẽ không hoạt động trong Webkit và chỉ nội dung sẽ không hoạt động trong Opera. Sử dụng cả hai sẽ đảm bảo nó luôn hoạt động, nhưng sẽ kích hoạt gọi lại hai lần trong Firefox. (Tôi có thể đã nhận sai các trình duyệt ...)
Jon Gjengset

2
htmllà bắt buộc đối với IE và lệnh gọi lại sẽ kích hoạt hai lần đối với hầu hết các trình duyệt khác. Tôi đang cố gắng tìm ra giải pháp cho cùng một vấn đề.
Simon Robb

9
Tôi đã đối phó với nó bằng cách tạo ra một lá cờ: var ranOne = false; $('body,html').animate({ scrollTop: scrollTo }, scrollTime, 'swing', function () { if (ranOne) { ...action... ranOne = false; } else { ranOne = true; } }); Nó có vẻ khó hiểu, nhưng việc phải sử dụng "body, html" ngay từ đầu đã là một điều khó hiểu. (Xin lỗi vì thiếu ngắt dòng, đoán các nhận xét không hiển thị chúng)
spinn

1
Không thể tin được! Tôi đã dành hàng giờ để cố gắng làm cho hoạt ảnh cuộn của mình hoạt động bình thường với $ ("html, body") để nó không kích hoạt hai lần và câu trả lời này chính là thứ đã cứu tôi! Cảm ơn!
Sảnh Vasily

172

Để nhận được một lệnh gọi lại để hoàn thành nhiều hoạt ảnh phần tử, hãy sử dụng các đối tượng hoãn lại.

$(".myClass").animate({
  marginLeft: "30em"
}).promise().done(function(){
  alert("Done animating");
});

Xem API jQuery để biết mô tả chi tiết về các Đối tượng Hứa hẹnTrì hoãn .


Điều này đã được giải quyết vấn đề về những gì chúng tôi muốn làm khi hoàn thành hoạt ảnh nhưng vấn đề về cuộc gọi hai lần và nhận được +1 cho điều đó, nhưng tôi không biết liệu quá trình hoạt ảnh có được gọi hai lần hay không ?!
QMaster

1
Quá trình tạo ảnh động không được gọi hai lần, lệnh gọi lại được gọi một lần cho mỗi phần tử đã chọn. Vì vậy, nếu bạn chọn 8 mục danh sách và chuyển chúng sang bên trái, lệnh gọi lại sẽ được thực hiện 8 lần. Giải pháp của tôi cung cấp cho bạn một cuộc gọi lại duy nhất khi cả 8 kết thúc.
Kevin B

@KevinB, giải pháp tốt và nó cũng giúp giải quyết các vấn đề gọi lại của riêng tôi. Cảm ơn.
lislis

Tôi đã nghĩ rằng đây là một câu trả lời hấp dẫn, nhưng không may là nó có hậu quả không lường trước được. Lời hứa không chỉ trì hoãn việc thực thi lệnh gọi lại cho đến khi các phần tử của tập hợp jQuery hoàn thành hoạt ảnh hiện tại (điều này sẽ rất tuyệt). Nó chỉ được giải quyết sau khi tất cả các hoạt ảnh đang chờ xử lý của tập hợp được thực hiện xong. Vì vậy, nếu hoạt ảnh thứ hai được thiết lập trong khi hoạt ảnh đầu tiên vẫn đang chạy, thì lệnh gọi lại dành cho hoạt ảnh đầu tiên sẽ không chạy cho đến khi hoạt ảnh thứ hai kết thúc. Xem thùng này .
hashchange

1
Điều đó đúng, nó đợi tất cả các hoạt ảnh hiện tại hoàn thành cho các phần tử đã chọn. Không đủ thông minh để chỉ đợi những cái bắt đầu trong chuỗi này (cũng không nên)
Kevin B
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.