jQuery: verkrijg hoogte van verborgen element in jQuery

Ik heb de hoogte nodig van een element dat zich in een verborgen div bevindt. Op dit moment laat ik de div zien, krijg ik de hoogte en verberg ik de bovenliggende div. Dit lijkt een beetje dom. Is er een betere manier?

Ik gebruik jQuery 1.4.2:

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

Antwoord 1, autoriteit 100%

Je zou zoiets als dit kunnen doen, hoewel een beetje hacky, vergeet positionals het al absoluut is:

var previousCss  = $("#myDiv").attr("style");
$("#myDiv").css({
    position:   'absolute', // Optional if #myDiv is already absolute
    visibility: 'hidden',
    display:    'block'
});
optionHeight = $("#myDiv").height();
$("#myDiv").attr("style", previousCss ? previousCss : "");

Antwoord 2, autoriteit 52%

Ik kwam hetzelfde probleem tegen met het verkrijgen van de breedte van verborgen elementen, dus schreef ik deze plug-in-aanroep jQuery Actualom het te repareren. In plaats van

$('#some-element').height();

gebruik

$('#some-element').actual('height');

geeft u de juiste waarde voor verborgen element of element heeft een verborgen bovenliggend element.

Volledige documentatie zie hier. Er staat ook een demo op de pagina.

Ik hoop dat dit helpt 🙂


Antwoord 3, autoriteit 22%

Je verwart twee CSS-stijlen, de weergavestijlen de zichtbaarheidsstijl.

Als het element is verborgen door de css-stijl voor zichtbaarheid in te stellen, zou u de hoogte moeten kunnen krijgen, ongeacht of het element zichtbaar is of niet, aangezien het element nog steeds ruimte inneemt op de pagina.

Als het element is verborgen door de css-stijl voor weergave te wijzigen in “none”, dan neemt het element geen ruimte in op de pagina en moet je het een weergavestijl geven waardoor het element in sommige gevallen wordt weergegeven. ruimte, op welk punt je de hoogte kunt krijgen.


Antwoord 4, autoriteit 16%

Ik heb soms mijn toevlucht genomen tot een beetje bedrog om hiermee om te gaan. Ik heb een jQuery-schuifbalkwidget ontwikkeld waarbij ik het probleem tegenkwam dat ik niet van tevoren weet of de schuifbare inhoud deel uitmaakt van een verborgen stukje opmaak of niet. Dit is wat ik deed:

// 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();
}

Dit werkt grotendeels, maar er is een duidelijk probleem dat zich kan voordoen. Als de inhoud die u kloont, is gestileerd met CSS die verwijzingen naar bovenliggende opmaak in hun regels bevat, bevat de gekloonde inhoud niet de juiste stijl en zal deze waarschijnlijk iets andere afmetingen hebben. Om dit te omzeilen, kunt u ervoor zorgen dat op de markeringen die u kloont CSS-regels zijn toegepast die geen verwijzingen naar bovenliggende markeringen bevatten.

Dit kwam ook niet voor mij met mijn Scroller-widget, maar om de juiste hoogte van het gekloonde element te krijgen, moet je de breedte instellen op dezelfde breedte van het ouderelement. In mijn geval werd een CSS-breedte altijd toegepast op het daadwerkelijke element, dus ik hoefde echter geen zorgen over te maken, maar als het element geen breedte heeft toegepast, moet u mogelijk een soort recursief doen Traversal van de DOM-voorouders van het element om de breedte van de juiste ouderelement te vinden.


5, Autoriteit 2%

Ik probeer de werkfunctie voor verborgen element te vinden, maar ik realiseer me dat CSS veel complex is dan iedereen denkt. Er zijn veel nieuwe lay-outtechnieken in CSS3 die mogelijk niet werken voor alle eerdere antwoorden zoals flexibele doos, raster, kolom of zelfs element in complexe ouderelement.

Flexibox-voorbeeld
Voer beeld beschrijving hier in

Ik denk dat de enige duurzame & eenvoudige oplossing is real-time weergave. Op dat moment zou de browser u die juiste elementgroottemoeten geven.

Helaas biedt JavaScript geen directe gebeurtenis om te melden wanneer een element wordt getoond of verborgen. Ik maak echter een functie op basis van DOM Attribute Modified API die de callback-functie uitvoert wanneer de zichtbaarheid van het element wordt gewijzigd.

$('[selector]').onVisibleChanged(function(e, isVisible)
{
    var realWidth = $('[selector]').width();
    var realHeight = $('[selector]').height();
    // render or adjust something
});

Ga voor meer informatie naar mijn project GitHub.

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

demo: http://jsbin.com/ETiGIre/7


Antwoord 6

In navolging van de oplossing van Nick Craver, zorgt het instellen van de zichtbaarheid van het element ervoor dat het nauwkeurige afmetingen krijgt. Ik heb deze oplossing heel vaak gebruikt. Omdat ik de stijlen echter handmatig moet resetten, ben ik dit omslachtig gaan vinden, aangezien ik door het wijzigen van de initiële positionering/weergave van het element in mijn CSS door ontwikkeling vaak vergeet de gerelateerde JavaScript-code bij te werken. De volgende code stelt de stijlen niet per se opnieuw in, maar verwijdert de inline-stijlen die door javascript zijn toegevoegd:

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

De enige veronderstelling hier is dat er geen andere inline-stijlen kunnen zijn, anders worden ze ook verwijderd. Het voordeel hier is echter dat de stijlen van het element worden teruggebracht naar wat ze waren in de CSS-stylesheet. Als gevolg hiervan kun je dit opschrijven als een functie waarbij een element wordt doorgegeven en een hoogte of breedte wordt geretourneerd.

Een ander probleem dat ik heb ondervonden bij het inline instellen van stijlen via js, is dat wanneer je te maken hebt met overgangen via css3, je gedwongen wordt om de gewichten van je stijlregels aan te passen om sterker te zijn dan een inline-stijl, wat soms frustrerend kan zijn.


Antwoord 7

Per definitie heeft een element alleen hoogte als het zichtbaar is.

Gewoon nieuwsgierig: waarom heb je de hoogte van een verborgen element nodig?

Een alternatief is om effectiefeen element te verbergen door het achter (met z-index) een soort overlay te plaatsen).


Antwoord 8

In mijn geval had ik ook een verborgen element dat me ervan weerhield de hoogtewaarde te krijgen, maar het was niet het element zelf, maar eerder een van zijn ouders… dus ik heb gewoon een vinkje geplaatst voor een van mijn plug-ins om kijk of het verborgen is, zoek anders het dichtstbijzijnde verborgen element. Hier is een voorbeeld:

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');
    }
}

In feite is dit een samensmelting van de reacties van Nick, Gregory en Ooglidloosheid om u de verbeterde methode van Gregory te laten gebruiken, maar beide methoden worden gebruikt voor het geval er iets in het stijlkenmerk zou moeten zitten dat u terug wilt zetten, en zoekt naar een bovenliggend element.

Mijn enige klacht over mijn oplossing is dat de lus door de ouders niet helemaal efficiënt is.


Antwoord 9

Een tijdelijke oplossing is om een ​​bovenliggende div te maken buiten het element waarvan u de hoogte wilt krijgen, een hoogte van ‘0’ toe te passen en eventuele overloop te verbergen. Neem vervolgens de hoogte van het onderliggende element en verwijder de overloopeigenschap van het bovenliggende element.

var height = $("#child").height();
// Do something here
$("#parent").append(height).removeClass("overflow-y-hidden");
.overflow-y-hidden {
  height: 0px;
  overflow-y: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent" class="overflow-y-hidden">
  <div id="child">
    This is some content I would like to get the height of!
  </div>
</div>

Snippet uitvouwen


Antwoord 10

Hier is een script dat ik heb geschreven om alle dimensiemethoden van jQuery voor verborgen elementen af ​​te handelen, zelfs afstammelingen van verborgen ouders. Merk op dat er natuurlijk een prestatiehit is als je dit gebruikt.

// 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);

Other episodes