Как я могу оживить элемент до его естественной высоты, используя jQuery

Я пытаюсь получить элемент, чтобы оживить его "естественную" высоту, то есть высоту, если бы она имела height: auto;.

Я придумал это:

var currentHeight = $this.height();
$this.css('height', 'auto');
var height = $this.height();
$this.css('height', currentHeight + 'px');

$this.animate({'height': height});

Есть ли лучший способ сделать это? Он чувствует себя немного взломанным.

Изменить: Здесь полный script, чтобы играть с тем, кто хочет протестировать.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html lang="en"> 
    <head>
        <title>jQuery</title>
        <style type="text/css">
            p { overflow: hidden; background-color: red; border: 1px solid black; }
            .closed { height: 1px; }
        </style>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>
        <script type="text/javascript">
        $().ready(function()
        {
            $('div').click(function()
            {
                $('p').each(function()
                {
                    var $this = $(this);

                    if ($this.hasClass('closed'))
                    {
                        var currentHeight = $this.height();
                        $this.css('height', 'auto');
                        var height = $this.height();
                        $this.css('height', currentHeight + 'px');

                        $this.animate({'height': height});
                    }
                    else
                    {
                        $this.animate({'height': 1});
                    }

                    $this.toggleClass('closed');
                });
            });
        });
        </script>
    </head>

    <body>

        <div>Click Me</div>
        <p>Hello - I started open</p>
        <p class="closed">Hello - I started closed</p>

    </body>
</html>

Ответ 1

Я мог бы предложить такое же хакерское решение... Клонировать элемент, позиционировать его вне поля зрения и получить его высоту... затем удалить его и оживить оригинал.

В стороне, вы также можете использовать $.slideUp() и $.slideDown():

$this.hasClass('closed') ? $(this).slideDown() : $(this).slideUp() ;

Если вам нужно сохранить строку 1px, вы можете применить ее к родительскому элементу:

<div style='border-top:1px solid #333333'>
  <div class='toggleMe'>Hello World</div>
</div>

И примените slideUp/Down на div.toggleMe.

Ответ 2

Я разрешаю себе ответить на эту тему, даже если на это уже давно ответили, потому что это просто помогло мне.

На самом деле, я не понимаю первый ответ: зачем открывать полузакрытый элемент, чтобы получить его высоту, а затем снова закрыть его?

В начале вы скрываете элемент так, чтобы отображалась только часть его, не так ли? Лучший способ (я полагаю) сделать это уже, с javascript. Таким образом, когда вы скрываете элемент onready, просто сохраняйте высоту orig в var, поэтому вам не нужно скрывать (onready) -show-save height-hide, чтобы иметь возможность переключать видимость элементов.

Посмотрите, что я сделал, он отлично работает:

$(document).ready(function(){
var origHeight = $("#foo").css('height');
$("#foo").css({"height" : "80px"});
$("#foo .toggle").bind("click", function(event){ toggleFoo(event, lastSearchesMidHeight); });
});

Здесь, когда вы вызываете свою функцию переключения, вы знаете, какова ваша первоначальная высота элемента без зависания.

Я написал это быстро, надеясь, что это может помочь кому-то в будущем.

Ответ 3

Самое простое решение, которое я нашел, - просто обернуть элемент контента с помощью div, который ограничен по высоте и установлен в overflow: hidden. Это обрезает внутренний элемент содержимого на высоту оберточного div. когда пользователь нажимает, наводит и т.д., чтобы показать всю высоту элемента содержимого - просто анимируйте обертывающий div на высоту внутреннего содержимого div.

Ответ 4

Я также хотел бы прослушивать этот старый поток, если можно, на случай, если мое решение поможет кому угодно. Моя конкретная ситуация такова: у меня есть div, которые заданы с максимальным значением высоты, которое ограничивает их тремя строками, и когда пользователь навешивает их, я хочу, чтобы они расширялись до их естественной высоты; и когда курсор мыши покидает div, я хочу, чтобы они сжимались до обрезанной высоты с максимумом в три строки. Мне нужно использовать свойство max-height CSS, а не height, потому что у меня есть div, содержащий только одну или две строки текста, и я не хочу, чтобы они были неоправданно высокими.

Я пробовал много решений в этом потоке, и тот, который работал у меня, был "хакерским предложением", включающим клонированные элементы, предложенные Джонатаном Сампсоном. Я перевел его идею в следующий код. Пожалуйста, не стесняйтесь предлагать улучшения.

Функции делегируются родительскому элементу для обработки div, созданного с помощью вызова Ajax. Класс div.overflow_expandable имеет следующее объявление: { max-height: 5em; overflow: hidden; }

$('#results').delegate('div.overflow_expandable', 'mouseenter', function() {
    var $this = $(this);

    // Close any other open divs
    $('#results div.overflow_expandable').not($(this)).trigger('mouseleave');

    // We need to convert the div current natural height (which is less than
    // or equal to its CSS max-height) to be a defined CSS 'height' property, 
    // which can then animate; and we unset max-height so that it doesn't 
    // prevent the div from growing taller.
    if (!$this.data('originalHeight')) {
        $this.data('originalHeight', $this.height());
        $this.data('originalMaxHeight', parseInt($this.css('max-height')));
        $this.css({ 'max-height':'none',
            height: $this.data('originalHeight') });
    }

    // Now slide out if the div is at its original height 
    // (i.e. in 'closed' state) and if its original height was equal to
    // its original 'max-height' (so when closed, it had overflow clipped)
    if ($this.height() == $this.data('originalHeight') && 
        $this.data('originalMaxHeight') == $this.data('originalHeight')) {
        // To figure out the new height, clone the original element and set 
        // its height to auto, then measure the cloned element new height;
        // then animate our div to that height
        var $clone = $this.clone().css({ height: 'auto', position: 'absolute', 
            zIndex: '-9999', left: '-9999px', width: $this.width() })
            .appendTo($this);
        $this.animate({ height: $clone.height() }, 'slow');
        $clone.detach();
    }
}).delegate('div.overflow_expandable', 'mouseleave', function() {
    var $this = $(this);
    // If the div has 'originalHeight' defined (it been opened before) and 
    // if it current height is greater than 'originalHeight' (it open 
    // now), slide it back to its original height
    if ($this.data('originalHeight') &&
        $this.height() > $this.data('originalHeight'))
        $this.animate({ height: $this.data('originalHeight') }, 'slow');
});

Ответ 5

Нашел этот пост и в конечном итоге использовал оригинальное предложение 1px от Greg - отлично работает!

Просто добавлен обратный вызов функции animate, чтобы установить высоту элемента в "auto", когда анимация заканчивается (в моем случае содержимое этого конкретного элемента может меняться и быть больше).

Ответ 6

$('div').click(function() { 
    if($('p').is(':hidden')) {
       $('p').slideUp();
    } else {
       $('p').slideDown(function() { $('p').css('height','1px'); });
    }
}

Это должно установить, что высота p-тегов будет равна 1px после того, как они закончатся.

Ответ 7

Это сработало для меня.

<div class="product-category">
    <div class="category-name">
        Cars
    </div>
    <div class="category-products" style="display: none; overflow: hidden;">
        <div class="product">Red Car</div>
        <div class="product">Green Car</div>
        <div class="product">Yellow Car</div>
    </div>
</div>

<script type="text/javascript">
$(document).ready(function() {
    $('.product-category .category-name').click(function() {
        if ($(this).parent().hasClass('active')) {
            $(this).parent().removeClass('active');
            var height = $(this).parent().find('.category-products').height();
            $(this).parent().find('.category-products').animate({ height : '0px' }, 600, function() {
                $(this).parent().find('.category-products').height(height).hide();
            });
        } else {
            $(this).parent().addClass('active');
            var height = $(this).parent().find('.category-products').height();
            $(this).parent().find('.category-products').height(0).show().animate({ height : height + 'px' }, 600);
        }
    });
});
</script>

Ответ 8

Мое решение состоит в том, чтобы сохранить в атрибуте data кнопки закрытия оригинальный размер контейнера (может быть сохранен также в самом контейнере, если вы не используете ту же кнопку, чтобы снова отобразить контейнер)

$(document).ready(function(){
    $('.infoBox .closeBtn').toggle(hideBox, showBox);
});

function hideBox()
{
    var parent = $(this).parent();

    $(this).text('Show').data('originalHeight', parent.css('height'));

    parent.animate({'height': 20});
    return false;
}

function showBox()
{
    var parent = $(this).parent();

    $(this).text('Hide');

    parent.animate({
        'height': $(this).data('originalHeight')
    });
    return false;
}

Ответ 9

Я хотел указать на этот ответ, который предлагает установить высоту для "show" с помощью функции animate(). Мне пришлось изменить стиль "slideUp", чтобы использовать высоту: "скрыть", чтобы работать с ней.