我需要得到一个元素的高度,在一个div是隐藏的。现在我显示div,获得高度,并隐藏父div。这看起来有点傻。有没有更好的办法?

我使用jQuery 1.4.2:

$select.show();
optionHeight = $firstOption.height(); //we can only get height if its visible
$select.hide();

当前回答

以尼克的回答为基础:

$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'});
optionHeight = $("#myDiv").height();
$("#myDiv").css({'position':'static','visibility':'visible', 'display':'none'});

我发现这样做更好:

$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'});
optionHeight = $("#myDiv").height();
$("#myDiv").removeAttr('style');

设置CSS属性将内联插入它们,这将覆盖你在CSS文件中的任何其他属性。通过删除HTML元素上的style属性,一切恢复正常,仍然是隐藏的,因为它最初是隐藏的。

其他回答

下面是我编写的一个脚本,用于处理隐藏元素的所有jQuery维度方法,甚至是隐藏父元素的后代。当然,请注意,使用这种方法会影响性能。

// Correctly calculate dimensions of hidden elements
(function($) {
    var originals = {},
        keys = [
            'width',
            'height',
            'innerWidth',
            'innerHeight',
            'outerWidth',
            'outerHeight',
            'offset',
            'scrollTop',
            'scrollLeft'
        ],
        isVisible = function(el) {
            el = $(el);
            el.data('hidden', []);

            var visible = true,
                parents = el.parents(),
                hiddenData = el.data('hidden');

            if(!el.is(':visible')) {
                visible = false;
                hiddenData[hiddenData.length] = el;
            }

            parents.each(function(i, parent) {
                parent = $(parent);
                if(!parent.is(':visible')) {
                    visible = false;
                    hiddenData[hiddenData.length] = parent;
                }
            });
            return visible;
        };

    $.each(keys, function(i, dimension) {
        originals[dimension] = $.fn[dimension];

        $.fn[dimension] = function(size) {
            var el = $(this[0]);

            if(
                (
                    size !== undefined &&
                    !(
                        (dimension == 'outerHeight' || 
                            dimension == 'outerWidth') &&
                        (size === true || size === false)
                    )
                ) ||
                isVisible(el)
            ) {
                return originals[dimension].call(this, size);
            }

            var hiddenData = el.data('hidden'),
                topHidden = hiddenData[hiddenData.length - 1],
                topHiddenClone = topHidden.clone(true),
                topHiddenDescendants = topHidden.find('*').andSelf(),
                topHiddenCloneDescendants = topHiddenClone.find('*').andSelf(),
                elIndex = topHiddenDescendants.index(el[0]),
                clone = topHiddenCloneDescendants[elIndex],
                ret;

            $.each(hiddenData, function(i, hidden) {
                var index = topHiddenDescendants.index(hidden);
                $(topHiddenCloneDescendants[index]).show();
            });
            topHidden.before(topHiddenClone);

            if(dimension == 'outerHeight' || dimension == 'outerWidth') {
                ret = $(clone)[dimension](size ? true : false);
            } else {
                ret = $(clone)[dimension]();
            }

            topHiddenClone.remove();
            return ret;
        };
    });
})(jQuery);

实际上,我有时会使用一些技巧来处理这个问题。我开发了一个jQuery滚动条小部件,在那里我遇到了一个问题,我不知道可滚动的内容是否是隐藏标记的一部分。以下是我所做的:

// try to grab the height of the elem
if (this.element.height() > 0) {
    var scroller_height = this.element.height();
    var scroller_width = this.element.width();

// if height is zero, then we're dealing with a hidden element
} else {
    var copied_elem = this.element.clone()
                      .attr("id", false)
                      .css({visibility:"hidden", display:"block", 
                               position:"absolute"});
    $("body").append(copied_elem);
    var scroller_height = copied_elem.height();
    var scroller_width = copied_elem.width();
    copied_elem.remove();
}

这在很大程度上是可行的,但有一个明显的问题可能会出现。如果要克隆的内容使用CSS样式,其中包含在规则中引用父标记,那么克隆的内容将不包含适当的样式,并且可能具有略微不同的度量。要解决这个问题,您可以确保要克隆的标记应用了CSS规则,这些规则不包括对父标记的引用。

另外,我的滚动部件没有出现这种情况,但是为了获得克隆元素的适当高度,您需要将宽度设置为与父元素相同的宽度。在我的例子中,CSS宽度总是应用于实际的元素,所以我不必担心这一点,但是,如果元素没有应用宽度,您可能需要对元素的DOM祖先进行某种递归遍历,以找到适当的父元素的宽度。

我试图找到隐藏元素的工作函数,但我意识到CSS比每个人想象的复杂得多。CSS3中有很多新的布局技术,这些技术可能并不适用于以前的所有问题,比如灵活的盒子、网格、列,甚至复杂的父元素中的元素。

flexibox例子

我认为唯一可持续且简单的解决方案是实时渲染。这时,浏览器将为您提供正确的元素大小。

遗憾的是,JavaScript不提供任何直接事件来通知元素何时显示或隐藏。然而,我创建了一些基于DOM属性修改API的函数,当元素的可见性发生变化时,将执行回调函数。

$('[selector]').onVisibleChanged(function(e, isVisible)
{
    var realWidth = $('[selector]').width();
    var realHeight = $('[selector]').height();

    // render or adjust something
});

更多信息,请访问我的项目GitHub。

https://github.com/Soul-Master/visible.event.js

演示:http://jsbin.com/ETiGIre/7

在我的环境中,我也有一个隐藏的元素阻止我获取高度值,但它不是元素本身,而是它的父元素之一……所以我只是检查了我的一个插件,看看它是否被隐藏,否则就找到最近的隐藏元素。这里有一个例子:

var $content = $('.content'),
    contentHeight = $content.height(),
    contentWidth = $content.width(),
    $closestHidden,
    styleAttrValue,
    limit = 20; //failsafe

if (!contentHeight) {
    $closestHidden = $content;
    //if the main element itself isn't hidden then roll through the parents
    if ($closestHidden.css('display') !== 'none') { 
        while ($closestHidden.css('display') !== 'none' && $closestHidden.size() && limit) {
            $closestHidden = $closestHidden.parent().closest(':hidden');
            limit--;
        }
    }
    styleAttrValue = $closestHidden.attr('style');
    $closestHidden.css({
        position:   'absolute',
        visibility: 'hidden',
        display:    'block'
    });
    contentHeight = $content.height();
    contentWidth = $content.width();

    if (styleAttrValue) {
        $closestHidden.attr('style',styleAttrValue);
    } else {
        $closestHidden.removeAttr('style');
    }
}

事实上,这是Nick, Gregory和Eyelidlessness的响应的合并,让您使用Gregory的改进方法,但使用这两种方法,以防在style属性中应该有您想要放回去的东西,并寻找父元素。

我对我的解决方案唯一的不满是,通过父节点的循环不是完全有效的。

根据定义,元素只有在可见时才有高度。

只是好奇:为什么需要隐藏元素的高度?

一种替代方法是通过将元素放在某种覆盖层的后面(使用z-index)来有效地隐藏元素。