好的,所以我提出了一个可行的解决方案......它并不像我希望的那样简单,但无论如何这里是工作代码:
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
在初始化时隐藏 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'});
}
}
});
}
谢谢阅读。