jQuery-получить ширину элемента, когда он не отображается (дисплей: нет)

похоже, что в jQuery, когда элемент не отображается width () возвращает 0. Имеет смысл, но мне нужно сделать ширину таблицы, чтобы установить ширину родителя, прежде чем я покажу родителя.

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

<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 всегда возвращает 0, так как он не виден (это мое предположение, так как он дает мне номер, когда он виден). Есть ли способ получить ширину таблицы, не делая Родительский видимым?

11 ответов


вот трюк, который я использовал. Он включает в себя добавление некоторых свойств CSS, чтобы jQuery думал, что элемент виден, но на самом деле он все еще скрыт.

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

это своего рода хак, но, похоже, он отлично работает для меня.

обновление

Я написал блоге, который охватывает эту тему. Метод, используемый выше, может быть проблематичным, поскольку вы сбрасываете свойства CSS на пустые значения. Что, если они ранее значения? Обновленное решение использует метод swap (), который был найден в исходном коде jQuery.

код из ссылки блог:

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

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

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

/ edit1: переписать функцию. теперь он меньше и может вызываться непосредственно на объекте

/ edit2: функция теперь будет вставлять клон сразу после исходного элемента вместо тела, что позволяет клону поддерживать унаследованный размеры.

$.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();

Спасибо за публикацию функции realWidth выше, это действительно помогло мне. Основываясь на функции" realWidth " выше, я написал, сброс CSS (причина описана ниже).

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" получает ширину существующего тега. При этом некоторые изображения теги. Проблема заключалась в том, что когда изображение дало CSS-измерение на ширину (или max-width), вы никогда не получите реальное измерение этого изображения. Возможно, img имеет " max-width: 100%", функция "realWidth" клонирует его и добавляет его к телу. Если исходный размер изображения больше, чем тело, то вы получаете размер тела, а не реальный размер этого изображения.


Я пытаюсь найти рабочую функцию для скрытого элемента, но я понимаю, что CSS намного сложнее, чем все думают. В CSS3 есть много новых методов компоновки, которые могут не работать для всех предыдущих ответов, таких как гибкая коробка, сетка, столбец или даже элемент внутри сложного родительского элемента.

пример flexibox enter image description here

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

к сожалению, JavaScript не предоставляет прямого события для уведомления, когда элемент показан или скрыт. Однако я создаю некоторую функцию на основе модифицированного API атрибута DOM, которая будет выполнять функцию обратного вызова при изменении видимости элемента.

$('[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


Если вам нужна ширина чего-то, что скрыто, и вы не можете отменить его по какой-либо причине, вы можете клонировать его, изменить CSS, чтобы он отображался со страницы, сделать его невидимым, а затем измерить его. Пользователь не будет мудрее, если он будет скрыт и удален после этого.

некоторые из других ответов здесь просто делают видимость скрытой, которая работает, но она займет пустое место на Вашей странице на долю секунды.

пример:

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

одно из решений, хотя оно не будет работать во всех ситуациях, - скрыть элемент, установив непрозрачность в 0. Полностью прозрачный элемент будет иметь ширину.

отступление заключается в том, что элемент по-прежнему будет занимать пространство, но это не будет проблемой во всех случаях.

например:

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

прежде чем взять ширину, сделайте Родительский дисплей, затем возьмите ширину и, наконец, сделайте Родительский дисплей скрытым. Так же, как следовать

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

самая большая проблема, пропущенная большинством решений здесь, заключается в том, что ширина элемента часто изменяется CSS на основе того, где он ограничен в html.

Если бы я должен был определить offsetWidth элемента, добавив его клон к телу, когда у него есть стили, которые применяются только в его текущей области, я бы получил неправильную ширину.

например:

//css

.модуль-контейнер .мой-Элем{ границы: 60px сплошной черный; }

теперь, когда я попробовать чтобы определить ширину my-elem в контексте тела, он выйдет на 120px. Вместо этого вы можете клонировать контейнер модуля, но ваш JS не должен знать эти детали.

Я не тестировал его, но по существу решение Soul_Master, похоже, является единственным, которое может работать должным образом. Но, к сожалению, глядя на реализацию, она, вероятно, будет дорогостоящей и плохой для производительности(как и большинство решений, представленных здесь.)

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


кроме ответ, размещенный Tim Banks, что последовало за решением моей проблемы, мне пришлось отредактировать одну простую вещь.

У кого-то еще может быть такая же проблема; я работаю с раскрывающимся списком Bootstrap в раскрывающемся списке. Но текст может быть шире как текущее содержимое на данный момент (и не так много хороших способов решить это через css).

Я:

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

вместо этого, который устанавливает контейнер в таблицу, которая всегда масштабируется в ширина, если содержимое шире.


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

при наведении мы можем рассчитать высоту элемента списка.