2010-01-31 31 views
14

Đây là mã của tôi, SetOpacity được gọi với giá trị sai, tại sao?setTimeout và vấn đề chức năng ẩn danh

function SetOpacity(eID, opacity){     
    eID.style.opacity = opacity/100; 
    eID.style.filter = 'alpha(opacity=' + opacity + ')'; 
} 
function fade(eID, startOpacity, endOpacity){   
    var timer = 0; 
    if (startOpacity < endOpacity) { 
     for (var i = startOpacity; i <= endOpacity; i++) { 
      setTimeout(function() {SetOpacity(eID, i);}, timer * 30); 
      timer++; 
     } 
    }   
} 

Trả lời

42

này nên làm việc:

for (var i = startOpacity; i <= endOpacity; i++) { 
    (function(opacity) { 
     setTimeout(function() {SetOpacity(eID, opacity);}, timer * 30); 
    })(i); 
    timer++; 
} 

này hoạt động như sau:

  • vòng lặp bên trong bạn tạo chức năng ẩn danh (function(...){...}) và ngay lập tức gọi nó với tham số (đó là lý do tại sao có ar e dấu ngoặc đơn xung quanh function(){}, vì vậy bạn có thể gọi nó là thêm () ở thông số kết thúc và vượt qua)
  • thông số được chuyển đến hàm ẩn danh này (i giá trị, là opacity bên trong hàm) là cục bộ cho hàm ẩn danh này, do đó chúng không thay đổi ở bước tiếp theo của vòng lặp, và bạn safelly có thể vượt qua chúng vào một chức năng ẩn danh (điều này tại setTimeout)

phiên bản gốc của bạn không làm việc vì:

  • chức năng của bạn thông qua với setTimeout giữ ref erence để biến i (không phải giá trị của nó), và nó được giá trị khi chức năng này được gọi, mà không phải là lúc thêm nó vào setTimeout
  • giá trị của biến này được thay đổi trong vòng lặp, và trước khi bạn nhận được đầu tiên setTimeout nó được giá trị endOpacity (giá trị cuối cùng từ for loop)

thật không may JavaScript chỉ có phạm vi chức năng, vì vậy nó sẽ không hoạt động nếu bạn tạo biến bên trong vòng lặp và gán giá trị thực tế mới, bởi vì bất cứ khi nào có một số var bên trong hàm, các biến đó được tạo tại thời điểm thực hiện hàm (và nhận giá trị undefined theo mặc định). Cách duy nhất (dễ) để tạo phạm vi mới là tạo hàm (có thể ẩn danh) và tạo biến mới bên trong chúng (tham số cũng là biến)

+0

+1 - Tôi cũng đã bắt đầu với một hàm ẩn danh. nhìn lại, tôi đoán bạn thanh lịch hơn. – Kobi

+0

bạn có thể giải thích điều này bằng (i) không? – ronik

+0

@ronik Tôi đã cập nhật câu trả lời của mình – MBO

5

Đây là sự cố đóng. Vào lúc bạn chạy hàm, i đã có tại endOpacity. Điều này sẽ hoạt động, bằng cách tạo một lần đóng khác:

function SetOpacityTimeout(eID, opacity, timer){ 
    setTimeout(function() {SetOpacity(eID, opacity);}, timer * 30); 
} 

function fade(eID, startOpacity, endOpacity){   
    var timer = 0; 
    if (startOpacity < endOpacity) { 
     for (var i = startOpacity; i <= endOpacity; i++) { 
      SetOpacityTimeout(eID,i,timer); 
      timer++; 
     } 
    }   
} 
+0

Tôi vẫn nhận được kết quả sai – ronik

+2

Bạn đã thử nghiệm điều này chưa? 'var opacity' vẫn nằm trong cùng phạm vi với' i', vì vậy nó vẫn sẽ bị phá vỡ, từ những gì tôi có thể nói. –

+0

@ Shtééf - bạn là chính xác. Làm việc về điều đó. – Kobi

1

Kobi có ý tưởng đúng về vấn đề này. Tôi đề nghị bạn sử dụng một khoảng thời gian để thay thế, mặc dù.

Dưới đây là một ví dụ: (chức năng setOpacity của bạn vẫn giữ nguyên, tôi rời nó ra ở đây.)

function fade(eID, startOpacity, endOpacity){ 
    var opacity = startOpacity; 
    SetOpacity(eID, opacity); 

    var interval = window.setInterval(function(){ 
     opacity++; 
     SetOpacity(eID, opacity); 

     // Stop the interval when done 
     if (opacity === endOpacity) 
      window.clearInterval(interval); 
    }, 30); 
} 
+0

cảm ơn, nhưng làm thế nào để làm điều đó với setTimeout? – ronik

+0

Giải pháp của MBO cũng sẽ hoạt động. –

1

Đây là ví dụ tôi đã dùng với jquery. "menuitem" là itemclass và jquery kiểm tra lớp "recentOut" để xem nó có cần trượt ngược lên hay không.

Mã nói cho chính nó.

$(".menuitem").mouseenter(
function(){ 
    $(this).addClass("over").removeClass("out").removeClass("recentlyOut"); 
    $(this).children(".sub").slideDown(); 
}); 
    $(".menuitem").mouseleave(
function(){ 

    $(this).addClass("out").addClass("recentlyOut").removeClass("over"); 
    setTimeout(function() 
     { 
      var bool = $(".recentlyOut").hasClass("over"); 
      if (!bool) 
      { 
    $(".recentlyOut").removeClass("recentlyOut").children(".sub").slideUp(); 
      } 
     } 
    , 400); 
} 
    ); 
Các vấn đề liên quan