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

Ответ 1

Вот трюк, который я использовал. Это связано с добавлением некоторых свойств 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));

Ответ 2

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

Ответ 3

На основе ответа Робертса, вот моя функция. Это работает для меня, если элемент или его родительский элемент исчезли через 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();

Ответ 4

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

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

Ответ 5

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

пример flexibox enter image description here

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

К сожалению, JavaScript не предоставляет никакого прямого события для уведомления, когда элемент отображается или скрыт. Тем не менее, я создаю некоторую функцию, основанную на DOM Attribute Modified 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

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

Ответ 6

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

Ответ 7

Перед тем, как принять ширину, отобразите родительский экран, затем возьмите ширину и, наконец, скройте родительский экран. Как и после

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

Ответ 8

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

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

Например:

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

Ответ 9

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

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

например:

//CSS

.module-container.my-elem { граница: 60px сплошная черная; }

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

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

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

Ответ 10

В дополнение к ответу, опубликованному Тимом Бэнксом, который последовал за решением моей проблемы, мне пришлось отредактировать одну простую вещь.

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

Я использовал:

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

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

Ответ 11

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

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

Ответ 12

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

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

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