2012-11-22 34 views
1

我想我知道爲什麼發生這種情況,但我不知道解決它的最好方法。這裏是你可以參考的jsFiddlejQuery動畫高度顯示/隱藏卡住

如果您嘗試打開和關閉jsFiddle中的子菜單(單擊任何鏈接旁邊的+圖標),然後在其完全關閉之前再次打開它,它將會卡住。現在打開菜單並嘗試打開它的一個子菜單,你會看到它的父母不能擴展以適應它。

我相信這個問題是hide過程jQuery期間,因爲造成應用內嵌高度的元素,如果你試圖在它之前打開它完成動畫它假定它是元素的最終高度。

我認爲每個元素的高度存儲在一開始就用它來動畫,但是這種方法的問題在於具有子菜單高度的菜單總是隨着其子菜單是否打開而改變而這個值永遠不是一個常數。

有無論如何告訴jQuery忽略元素的內聯高度並計算它的真實高度應該是什麼?

這裏是jQuery的使用,HTML和CSS請參閱的jsfiddle因爲他們是相當漫長:

jQuery(document).ready(function($){ 
    var legacyMode = $('html').hasClass('oldie'); 
    var titles = {normal: "Show sub-topics", active: "Hide sub-topics"}; 

    var sub_sections = $('ul#map li:has(ul.child)'); 

    sub_sections.each(function() { 
     if (!$(this).find('li.active').length && !$(this).hasClass('active')) { 
      var toggle = $('<a class="toggle" href="#"></a>').attr('title', titles.normal).insertBefore($(this).children('ul.child')); 
      var child = $(this).children('ul.child').hide(); 
      toggle.data('container', this); 
     } 
    }); 

    $('a.toggle').click(function (event) { 
     event.preventDefault(); 
     var target = $(this).siblings('ul.child'); 
     if($(this).hasClass('active')) { 
      toggleDisplay(target, false); 
      $(this).removeClass('active').attr('title', titles.normal); 
     } else { 
      toggleDisplay(target, true); 
      $(this).addClass('active').attr('title', titles.active); 
     } 
     function toggleDisplay(target, on) { 
      var mode = (on) ? "show" : "hide"; 
      if (!legacyMode) { 
       target.stop(true, false).animate({height: mode, opacity: mode}, 500); 
      } else { 
       // Omits opacity to avoid using proprietary filters in legacy browsers 
       target.stop(true, false).animate({height: mode}, 500); 
      } 
     } 
    }); 
});​ 

回答

0

好了,所以我做了一個可行的解決方案......它並不像我想的希望,但無論如何這裏相當直線前進是工作代碼:

jQuery(document).ready(function($){ 
    var legacyMode = $('html').hasClass('oldie'); 
    var titles = {normal: "Show sub-topics", active: "Hide sub-topics"}; 

    var sub_sections = $('ul#map li:has(ul.child)'); 

    sub_sections.each(function() { 
     if (!$(this).find('li.active').length && !$(this).hasClass('active')) { 
      var child = $(this).children('ul.child'); 
      if (!legacyMode) { 
       child.css({height : '0px', opacity : 0, display: 'none'}); 
      } else { 
       // Omits opacity to avoid using proprietary filters in legacy browsers 
       child.css({height : '0px', display: 'none'}); 
      } 
      var toggle = $('<a class="toggle" href="#"></a>').attr('title', titles.normal).insertBefore(child); 
      toggle.data('container', this); 
     } 
    }); 

    $('a.toggle').click(function (event) { 
     event.preventDefault(); 
     var target = $(this).siblings('ul.child'); 
     if($(this).hasClass('active')) { 
      toggleDisplay(target, false); 
      $(this).removeClass('active').attr('title', titles.normal); 
     } else { 
      toggleDisplay(target, true); 
      $(this).addClass('active').attr('title', titles.active); 
     } 
     function toggleDisplay(target, on) { 
      var targetOpacity = 0; 
      var targetHeight = 0; 
      if (on) { 
       // Get height of element once expanded by creating invisible clone 
       var clone = target.clone().attr("id", false).css({visibility:"hidden", display:"block", position:"absolute", height:""}).appendTo(target.parent()); 
       targetHeight = clone.height(); 
       targetOpacity = 1; 
       console.log(clone.height()); 
       clone.remove(); 
       target.css({display : 'block'}); 
      } 
      if (!legacyMode) { 
       target.stop(true, false).animate({height: targetHeight + "px" , opacity: targetOpacity}, { 
        duration: 500, 
        complete: function() { 
         if (on) { 
          $(this).css({height : '', opacity : ''}); 
         } else { 
          $(this).css({display : 'none'}); 
         } 
        } 
       }); 
      } else { 
       // Omits opacity to avoid using proprietary filters in legacy browsers 
       target.stop(true, false).animate({height: targetHeight + "px"}, { 
        duration: 500, 
        complete: function() { 
         if (on) { 
          $(this).css({height : ''}); 
         } else { 
          $(this).css({display : 'none'}); 
         } 
        } 
       });   
      } 
     } 
    }); 
});​ 

看到它在行動:http://jsfiddle.net/xetCd/24/(點擊任何次數的任意次數的切換的任何組合都應該保持平穩)。

測試了:IE7,IE8(設置var legacyModetrue以獲得最佳效果),火狐15,鉻23

它是如何工作的?那麼我不再使用showhide動畫目標,因爲它們不夠靈活。爲此,我不得不有點不同隱藏ul s的初始化:在

var child = $(this).children('ul.child'); 
if (!legacyMode) { 
    child.css({height : '0px', opacity : 0, display: 'none'}); 
} else { 
    // Omits opacity to avoid using proprietary filters in legacy browsers 
    child.css({height : '0px', display: 'none'}); 
} 
var toggle = $('<a class="toggle" href="#"></a>').attr('title', titles.normal).insertBefore(child);​ 

現在這種多汁位,如何計算元素的目標高度時,它可能是在動畫中的任何階段,有任何數量的子菜單的打開或關閉。我通過創建元素的visibility : hidden副本並強制它佔用它的常規高度來解決此問題,我也給它position : absolute,以便它看起來不佔用文檔中的任何空間。我抓住它的高度並將其刪除:

var targetOpacity = 0; 
var targetHeight = 0; 
if (on) { 
    // Get height of element once expanded by creating invisible clone 
    var clone = target.clone().attr("id", false).css({visibility:"hidden", display:"block", position:"absolute", height:""}).appendTo(target.parent()); 
    targetHeight = clone.height(); 
    targetOpacity = 1; 
    console.log(clone.height()); 
    clone.remove(); 
    target.css({display : 'block'}); 
}​ 

然後,我的動畫,並確保重置display並刪除height(這樣子菜單的可擴展他們的父母)性質:

if (!legacyMode) { 
    target.stop(true, false).animate({height: targetHeight + "px" , opacity: targetOpacity}, { 
     duration: 500, 
     complete: function() { 
      if (on) { 
       $(this).css({height : '', opacity : ''}); 
      } else { 
       $(this).css({display : 'none'}); 
      } 
     } 
    }); 
} else { 
    // Omits opacity to avoid using proprietary filters in legacy browsers 
    target.stop(true, false).animate({height: targetHeight + "px"}, { 
     duration: 500, 
     complete: function() { 
      if (on) { 
       $(this).css({height : ''}); 
      } else { 
       $(this).css({display : 'none'}); 
      } 
     } 
    });   
}​ 

謝謝閱讀。

2

這是發生,因爲屬性的你傳遞的stop()方法,animate()前。

方法stop(true, false)中的第二個屬性指定動畫是否應跳轉到最後一幀。在你的代碼中,因爲它是false,所以在錨標籤上登記下一個click的階段會卡住。

將其更改爲.stop(true, true),它將按預期工作!

+0

謝謝,但我想它從它結束的框架動畫。這不可能嗎? –

+0

在這種情況下,您需要稍微修改代碼。在動畫過程開始之前向該元素添加一個'animating'類,並在動畫完成後將其刪除。檢查元素是否具有動畫類,如果沒有,則只運行show hide。更新你的小提琴:http://jsfiddle.net/xetCd/7/ – kayen

+0

我認爲你誤解了,代碼提出了一些新的問題,特別是在可用性部門,但+1的努力。我不想像'.stop(true,false)'那樣工作,但不會卡住。所以它從用戶決定切換它的任何點開始動畫。 –

0

我遇到了與jQuery 1.8.3相同的問題,並發現升級到v1.12.2修復了它。對於遇到此問題的其他人來說,這可能是一個解決方案。讓我知道如果這不適合你。