it-swarm.com.de

jQuery - Breite des Elements abrufen, wenn es nicht sichtbar ist (Anzeige: Keine)

Es scheint, als würde in jQuery ein Element nicht sichtbar sein. Width () gibt 0 zurück. Macht Sinn, aber ich muss die Breite einer Tabelle ermitteln, um die Breite des übergeordneten Elements festzulegen, bevor ich das übergeordnete Element zeige.

Wie unten erwähnt, gibt es Text im übergeordneten Element, der das übergeordnete Element schief und ungünstig aussehen lässt. Ich möchte, dass das übergeordnete Element nur so breit ist wie die Tabelle und den Textumbruch haben soll.

<div id="parent">
    Text here ... Can get very long and skew the parent
    <table> ... </table>
    Text here too ... which is why I want to shrink the parent based on the table
</div>

CSS:

#parent
{
    display: none;
}

Javascript:

var tableWidth = $('#parent').children('table').outerWidth();
if (tableWidth > $('#parent').width())
{
    $('#parent').width(tableWidth);
}

tableWidth gibt immer 0 zurück, da es nicht sichtbar ist (ist meine Vermutung, da es mir eine Nummer gibt, wenn es sichtbar ist). Gibt es eine Möglichkeit, die Breite der Tabelle zu ermitteln, ohne das übergeordnete Element sichtbar zu machen?

103
Martin

Hier ist ein Trick, den ich verwendet habe. Dazu müssen einige CSS-Eigenschaften hinzugefügt werden, damit jQuery den Eindruck hat, dass das Element sichtbar ist, es ist jedoch immer noch verborgen.

var $table = $("#parent").children("table");
$table.css({ position: "absolute", visibility: "hidden", display: "block" });
var tableWidth = $table.outerWidth();
$table.css({ position: "", visibility: "", display: "" });

Es ist eine Art Hack, aber es scheint gut für mich zu funktionieren.

UPDATE

Ich habe seitdem ein Blogpost geschrieben, das dieses Thema behandelt. Die oben verwendete Methode kann problematisch sein, da Sie die CSS-Eigenschaften auf leere Werte zurücksetzen. Was wäre, wenn sie zuvor Werte hatten? Die aktualisierte Lösung verwendet die im jQuery-Quellcode gefundene Methode swap ().

Code aus dem referenzierten Blogpost:

//Optional parameter includeMargin is used when calculating outer dimensions  
(function ($) {
$.fn.getHiddenDimensions = function (includeMargin) {
    var $item = this,
    props = { position: 'absolute', visibility: 'hidden', display: 'block' },
    dim = { width: 0, height: 0, innerWidth: 0, innerHeight: 0, outerWidth: 0, outerHeight: 0 },
    $hiddenParents = $item.parents().andSelf().not(':visible'),
    includeMargin = (includeMargin == null) ? false : includeMargin;

    var oldProps = [];
    $hiddenParents.each(function () {
        var old = {};

        for (var name in props) {
            old[name] = this.style[name];
            this.style[name] = props[name];
        }

        oldProps.Push(old);
    });

    dim.width = $item.width();
    dim.outerWidth = $item.outerWidth(includeMargin);
    dim.innerWidth = $item.innerWidth();
    dim.height = $item.height();
    dim.innerHeight = $item.innerHeight();
    dim.outerHeight = $item.outerHeight(includeMargin);

    $hiddenParents.each(function (i) {
        var old = oldProps[i];
        for (var name in props) {
            this.style[name] = old[name];
        }
    });

    return dim;
}
}(jQuery));
91
Tim Banks
function realWidth(obj){
    var clone = obj.clone();
    clone.css("visibility","hidden");
    $('body').append(clone);
    var width = clone.outerWidth();
    clone.remove();
    return width;
}
realWidth($("#parent").find("table:first"));
38
Fábio Paiva

Basierend auf der Antwort von Roberts ist hier meine Funktion .. Dies funktioniert für mich, wenn das Element oder sein übergeordnetes Element über jQuery ausgeblendet wurde, entweder innere oder äußere Dimensionen erhalten kann und auch die Versatzwerte zurückgibt.

/ edit1: Schreibe die Funktion neu. Es ist jetzt kleiner und kann direkt am Objekt aufgerufen werden

/ edit2: Die Funktion fügt den Klon jetzt direkt nach dem ursprünglichen Element anstelle des Hauptteils ein, sodass der Klon vererbte Dimensionen beibehalten kann.

$.fn.getRealDimensions = function (outer) {
    var $this = $(this);
    if ($this.length == 0) {
        return false;
    }
    var $clone = $this.clone()
        .show()
        .css('visibility','hidden')
        .insertAfter($this);        
    var result = {
        width:      (outer) ? $clone.outerWidth() : $clone.innerWidth(), 
        height:     (outer) ? $clone.outerHeight() : $clone.innerHeight(), 
        offsetTop:  $clone.offset().top, 
        offsetLeft: $clone.offset().left
    };
    $clone.remove();
    return result;
}

var dimensions = $('.hidden').getRealDimensions();
8
Marco Kerwitz

Ich versuche, eine funktionierende Funktion für versteckte Elemente zu finden, aber ich stelle fest, dass CSS viel komplexer ist, als jeder denkt. Es gibt viele neue Layouttechniken in CSS3, die möglicherweise nicht für alle vorherigen Antworten geeignet sind, z. B. für flexible Boxen, Raster, Spalten oder sogar Elemente in komplexen übergeordneten Elementen.

flexibox-Beispielenter image description here

Ich denke, die einzige nachhaltige und einfache Lösung ist Echtzeit-Rendering. Zu diesem Zeitpunkt sollte der Browser Ihnen das richtige Elementgröße geben. 

Leider bietet JavaScript kein direktes Ereignis, um zu benachrichtigen, wenn ein Element angezeigt oder ausgeblendet wird. Ich erstelle jedoch eine Funktion basierend auf der DOM Attribute Modified API, die die Callback-Funktion ausführt, wenn die Sichtbarkeit des Elements geändert wird.

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

    // render or adjust something
});

Für weitere Informationen besuchen Sie bitte mein Projekt GitHub.

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

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

3
Soul_Master

Vielen Dank, dass Sie die RealWidth-Funktion oben veröffentlicht haben, sie hat mir wirklich geholfen. Basierend auf der "realWidth" -Funktion oben schrieb ich einen CSS-Reset (Grund beschrieben).

function getUnvisibleDimensions(obj) {
    if ($(obj).length == 0) {
        return false;
    }

    var clone = obj.clone();
    clone.css({
        visibility:'hidden',
        width : '',
        height: '',
        maxWidth : '',
        maxHeight: ''
    });
    $('body').append(clone);
    var width = clone.outerWidth(),
        height = clone.outerHeight();
    clone.remove();
    return {w:width, h:height};
}

"realWidth" erhält die Breite eines vorhandenen Tags. Ich habe das mit einigen Image-Tags getestet. Das Problem war, wenn das Bild CSS-Abmessungen pro Breite (oder maximaler Breite) zugewiesen hat, erhalten Sie niemals die tatsächliche Größe dieses Bildes. Vielleicht hat das img "max-width: 100%", die Funktion "realWidth" kopiert es und fügt es dem Körper hinzu. Wenn die Originalgröße des Bildes größer als der Körper ist, wird die Größe des Körpers und nicht die tatsächliche Größe des Bildes angezeigt. 

3
Robert

Wenn Sie die Breite eines verborgenen Objekts benötigen und Sie es aus irgendeinem Grund nicht ausblenden können, können Sie es klonen, das CSS so ändern, dass es außerhalb der Seite angezeigt wird, es unsichtbar machen und es dann messen. Der Benutzer wird nicht klüger sein, wenn er ausgeblendet und anschließend gelöscht wird.

Bei einigen der anderen Antworten wird nur die Sichtbarkeit ausgeblendet, die funktioniert, aber es wird für einen Bruchteil einer Sekunde eine leere Stelle auf Ihrer Seite einnehmen.

Beispiel:

$itemClone = $('.hidden-item').clone().css({
        'visibility': 'hidden',
        'position': 'absolute',
        'z-index': '-99999',
        'left': '99999999px',
        'top': '0px'
    }).appendTo('body');
var width = $itemClone.width();
$itemClone.remove();
3
rannmann

Eine Lösung, die jedoch nicht in allen Situationen funktioniert, ist das Ausblenden des Elements, indem die Deckkraft auf 0 gesetzt wird. Ein vollständig transparentes Element hat die Breite. 

Der Nachteil ist, dass das Element immer noch Platz beansprucht, dies ist jedoch nicht in allen Fällen ein Problem. 

Zum Beispiel:

$(img).css("opacity", 0)  //element cannot be seen
width = $(img).width()    //but has width
2
Jake

Bevor Sie die Breite übernehmen, lassen Sie die übergeordnete Anzeige anzeigen, dann nehmen Sie die Breite und lassen Sie schließlich die übergeordnete Anzeige ausblenden. Genau wie folgt 

$('#parent').show();
var tableWidth = $('#parent').children('table').outerWidth();
 $('#parent').hide();
if (tableWidth > $('#parent').width())
{
    $('#parent').width() = tableWidth;
}
2
sourcecode

Das größte Problem, das bei den meisten Lösungen hier übersehen wird, ist, dass die Breite eines Elements von CSS häufig geändert wird, je nachdem, wo sie in HTML definiert sind.

Wenn ich offsetWidth eines Elements ermitteln wollte, indem ich einen Klon an den Körper anfügte, wenn es Stile hat, die nur in seinem aktuellen Geltungsbereich gelten, würde ich die falsche Breite erhalten.

zum Beispiel:

// css

.module-container .my-elem { Rand: 60px durchgehend schwarz; }

jetzt, wenn ich versuche, die Breite meines elems im körperlichen Kontext zu bestimmen, wird es um 120px rauskommen. Sie können stattdessen den Modulcontainer klonen, aber Ihr JS sollte diese Details nicht kennen.

Ich habe es nicht getestet, aber im Grunde scheint die Lösung von Soul_Master die einzige zu sein, die richtig funktionieren könnte. Aber wenn man sich die Implementierung ansieht, wird dies leider kostspielig und schlecht für die Leistung sein (da die meisten der hier vorgestellten Lösungen ebenfalls sind).

Verwenden Sie, wenn überhaupt, Sichtbarkeit: stattdessen versteckt. Dadurch wird das Element immer noch gerendert, sodass Sie die Breite ohne viel Aufwand berechnen können.

1
Code Novitiate

Zusätzlich zu der Antwort von Tim Banks , die zur Lösung meines Problems folgte, musste ich eine einfache Sache bearbeiten.

Jemand anderes könnte das gleiche Problem haben. Ich arbeite mit einem Bootstrap Dropdown in einem Dropdown. Der Text kann jedoch an dieser Stelle breiter sein als der aktuelle Inhalt (und es gibt nicht viele gute Möglichkeiten, dies durch CSS zu lösen).

Ich benutzte: 

$table.css({ position: "absolute", visibility: "hidden", display: "table" });

stattdessen wird der Container auf eine Tabelle gesetzt, die bei breiteren Inhalten immer in der Breite skaliert.

0
Mathijs Segers
jQuery(".megamenu li.level0 .dropdown-container .sub-column ul .level1").on("mouseover", function () {
    var sum = 0;
    jQuery(this).find('ul li.level2').each(function(){
    sum -= jQuery(this).height();
    jQuery(this).parent('ul').css('margin-top', sum / 1.8);
    console.log(sum);
    });
});

Beim Schweben können wir die Höhe des Listenelements berechnen. 

0
rajashekar

Wie bereits erwähnt, garantieren die Methoden "Klonen" und "Andernorts anfügen" nicht die gleichen Ergebnisse, da das Styling möglicherweise unterschiedlich ist.

Unten ist mein Ansatz. Es fährt die Eltern auf der Suche nach dem für das Verstecken verantwortlichen Elternteil aufwärts und blendet es dann vorübergehend aus, um die erforderliche Breite, Höhe usw. zu berechnen.

    var width = parseInt($image.width(), 10);
    var height = parseInt($image.height(), 10);

    if (width === 0) {

        if ($image.css("display") === "none") {

            $image.css("display", "block");
            width = parseInt($image.width(), 10);
            height = parseInt($image.height(), 10);
            $image.css("display", "none");
        }
        else {

            $image.parents().each(function () {

                var $parent = $(this);
                if ($parent.css("display") === "none") {

                    $parent.css("display", "block");
                    width = parseInt($image.width(), 10);
                    height = parseInt($image.height(), 10);
                    $parent.css("display", "none");
                }
            });
        }
    }
0
Ibraheem