我想我知道为什么会这样,但我不确定解决问题的最佳方法。这是您可以参考的jsFiddle。
如果您尝试打开和关闭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 :(得分:2)
这是因为您在animate()
之前传递stop()方法的属性。
方法stop(true, false)
中的第二个属性指定动画是否应跳转到最后一帧。在您的代码中,由于它是false
,因此它会在锚标记旁边注册click
的阶段停滞不前。
将其更改为.stop(true, true)
,它将按预期工作!
答案 1 :(得分: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 legacyMode
设置为true
以获得最佳效果),Firefox 15,Chrome 23
它是如何工作的?好吧,我不再使用show
和hide
动画目标,因为这些目标不够灵活。出于这个原因,我必须在初始化时隐藏ul
一点点:
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 :(得分:0)
我遇到了与jQuery 1.8.3相同的问题,发现升级到v1.12.2修复了它。对于其他遇到此问题的人来说,这可能是一个解决方案。如果这对您不起作用,请告诉我。