jQuery: Отримайте висоту прихованого елемента в jQuery


249

Мені потрібно отримати висоту елемента, який знаходиться в межах прихованого діва. Зараз я показую дів, отримую висоту і ховаю батьківський дів. Це здається трохи дурним. Чи є кращий спосіб?

Я використовую jQuery 1.4.2:

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

42
+1 Ваше рішення прикладу насправді краще, ніж будь-яка відповідь, хай.
Тім Сантефорд

9
Я не погоджуюся з Тімом. За допомогою цього рішення є ймовірність, що дисплей може мерехтіти, оскільки ви фактично показуєте предмет, а потім ховаєте його. Навіть незважаючи на те, що рішення Nicks є більш складним, воно не має шансів мерехтіти на дисплеї, оскільки батьківський div ніколи не відображається.
Хамфрі

можливий дублікат jQuery - Отримати
ширину


5
Гаррі, насправді ви дізналися, що ваш код не працює в IE, не в цьому рішенні. Ідіть налагоджуйте свій код :)
Gavin,

Відповіді:


181

Ви можете зробити щось подібне, хоч трохи хакі, забудьте, positionякщо це вже абсолютно:

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

17
Я зведений вище код у плагін jQ jsbin.com/ihakid/2 . Я також використовую клас та перевіряю, чи також батьки / батьки приховані.
hitautodestruct

3
+1 Це чудово працює. Просто пам’ятайте, що батьки елемента також повинні відображатися. Це мене збентежило кілька хвилин. Крім того, якщо елемент є position:relative, ви, звичайно, захочете встановити це після, а не static.
Майкл Міор

6
При використанні цього методу цільовий елемент часто може змінювати форму. Тож отримання висоти та / або ширини датчика, коли він розташований абсолютно не може бути дуже корисним.
Джеремі Рікеттс

2
@Gavin це запобігає розрахунку поповнення та будь-якому мерехтінню для користувача, тож це і дешевше, і менш нав'язливе.
Нік Крейвер

2
@hitautodestruct, я змінив ваш плагін запиту, щоб перевірити, що цей елемент фактично прихований. jsbin.com/ihakid/58
Прасад

96

Я зіткнувся з тією ж проблемою з отриманням прихованої ширини елементів, тому я написав цей виклик плагіна jQuery Actual, щоб виправити його. Замість використання

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

використання

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

дасть вам правильне значення для прихованого елемента або елемента має прихований батьківський елемент.

Повну документацію дивіться тут . Також на сторінці є демонстраційна версія.

Сподіваюся, що це допоможе :)


3
Так, це допомагає! 2015 рік, і це все ще допомагає. Ви говорите "старіші версії jquery" на веб-сайті Actual - однак - це все ще потрібно в v2.1.3, принаймні, це було в моїй ситуації.
LpLrich

Дякую! Я використовував цей плагін для читання та встановлення висоти елементів (це робиться динамічно), прихованих спочатку в гармошках
alds

Дивовижний плагін! Я намагався все, щоб отримати ширину ключа всередині модалу, коли встановлено 100%, і нічого не вийшло. налаштуйте це за 5 секунд і працювали чудово!
Крейг Хоуелл

@ben Посилання розірвано.
Сахін Прасад

39

Ви плутаєте два стилі CSS, стиль відображення та стиль видимості .

Якщо елемент приховано, встановивши стиль css видимості, то ви повинні мати можливість отримати висоту незалежно від того, видно елемент чи ні, оскільки елемент все ще займає місце на сторінці .

Якщо елемент приховано, змінивши стиль css відображення на "none", елемент не займе місця на сторінці, і вам доведеться надати йому стиль відображення, який призведе до того, що елемент відобразиться в деякому просторі, на в якій точці ви можете отримати висоту.


спасибі за це. моя проблема бере участь в клітинку таблиці, і установка visibilityна hiddenне вирішити мою проблему, але це дало мені ідею набору position: fixed; top: 100%і він працює як шарм!
Jayen

Тепер я розумію, чому висота не відображається за допомогою дисплея: жодних елементів. Дякую велике за чудове пояснення.
FrenkyB

30

Я фактично вдався до трохи хитрощів, щоб часом боротися з цим. Я розробив віджет прокрутки jQuery, в якому зіткнувся з проблемою, про яку я не знаю достроково, чи вміст прокрутки є частиною прихованого фрагмента розмітки чи ні. Ось що я зробив:

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

Це працює здебільшого, але існує очевидна проблема, яка потенційно може виникнути. Якщо вміст, який ви клонуєте, стилізований за допомогою CSS, який включає в себе посилання на батьківську розмітку у своїх правилах, вміст клонованого не містить відповідного стилю, і, ймовірно, має дещо інші вимірювання. Щоб обійти це, ви можете переконатися, що розмітка, яку ви клонуєте, має до неї застосовані правила CSS, які не містять посилань на батьківську розмітку.

Крім того, це не придумало для мене віджет прокрутки, але щоб отримати відповідну висоту клонованого елемента, вам потрібно встановити ширину на ту ж ширину батьківського елемента. У моєму випадку ширина CSS завжди застосовувалася до фактичного елемента, тому мені не довелося з цього приводу хвилюватися, однак, якщо елемент не має до нього застосованої ширини, можливо, вам доведеться зробити якийсь рекурсивний обхід походження DOM елемента, щоб знайти відповідну ширину батьківського елемента.


У цьому є цікава проблема. Якщо елемент вже є блоковим елементом, клон займе всю ширину корпусу (за винятком набивання корпусу або поля), що відрізняється від розміру всередині контейнера.
Мелігія

16

Спираючись далі на відповідь користувача Nick та плагін користувача hitautodestruct користувача на JSBin, я створив подібний плагін jQuery, який отримує і ширину, і висоту, і повертає об'єкт, що містить ці значення.

Його можна знайти тут: http://jsbin.com/ikogez/3/

Оновлення

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

Це прекрасно працює:

/**
 * getSize plugin
 * This plugin can be used to get the width and height from hidden elements in the DOM.
 * It can be used on a jQuery element and will retun an object containing the width
 * and height of that element.
 *
 * Discussed at StackOverflow:
 * http://stackoverflow.com/a/8839261/1146033
 *
 * @author Robin van Baalen <robin@neverwoods.com>
 * @version 1.1
 * 
 * CHANGELOG
 *  1.0 - Initial release
 *  1.1 - Completely revamped internal logic to be compatible with javascript-intense environments
 *
 * @return {object} The returned object is a native javascript object
 *                  (not jQuery, and therefore not chainable!!) that
 *                  contains the width and height of the given element.
 */
$.fn.getSize = function() {    
    var $wrap = $("<div />").appendTo($("body"));
    $wrap.css({
        "position":   "absolute !important",
        "visibility": "hidden !important",
        "display":    "block !important"
    });

    $clone = $(this).clone().appendTo($wrap);

    sizes = {
        "width": $clone.width(),
        "height": $clone.height()
    };

    $wrap.remove();

    return sizes;
};

ваш код невірний. Вам потрібно відноситься до вихідного пункту, який не видно. sizes = {"width": $wrap.width(), "height": $wrap.height()};this
jackJoe

@jackJoe Я використовую цей код досить довго без проблем. У кращому випадку я б сказав, що мені потрібно $ clone.width () замість 'цього'. Не $ wrap, оскільки я хочу розмір елемента всередині обгортання. Обгортка може бути 10000x10000px, тоді як елемент, який я хочу виміряти, все ще становить 30x40px.
Робін ван Бален

Навіть націлювання на $wrapце нормально (принаймні в моїх тестах). Я спробував з, thisі, очевидно, він не вловив би розмір, оскільки thisвсе ще відноситься до прихованого елемента.
jackJoe

1
Дякую @jackJoe, я зараз оновив приклад коду.
Робін ван Баален

12

Спираючись далі на відповідь Ніка:

$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'});
optionHeight = $("#myDiv").height();
$("#myDiv").css({'position':'static','visibility':'visible', 'display':'none'});

Я знайшов, що краще це зробити:

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

Якщо встановити атрибути CSS, вони вставлятимуть їх у рядок, що замінить будь-які інші атрибути у вашому CSS-файлі. Видаляючи атрибут стилю з елемента HTML, все повертається до нормального та все ще приховане, оскільки це було приховано в першу чергу.


1
$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'}); optionHeight = $("#myDiv").height(); $("#myDiv").css({'position':'','visibility':'', 'display':''});
Аарон

9
... якщо ви вже не мали вбудованих стилів на елементі. Що було б у випадку, якщо ви заховали елемент за допомогою jQuery.
Muhd

4

Ви також можете розташувати прихований роздільник на екрані з від'ємним запасом, а не використовувати дисплей: жоден, як і техніка заміни текстового відступу.

напр.

position:absolute;
left:  -2000px;
top: 0;

Таким чином висота () все ще доступна.


3

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

Приклад flexibox введіть тут опис зображення

Я думаю, що єдиним стійким та простим рішенням є надання в режимі реального часу . У той час браузер повинен надати вам правильний розмір елемента .

На жаль, 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


Дякую за вашу відповідь. Це мене надихнуло і на використання MutationObservers. Але зауважте, що ваша бібліотека перевіряє лише зміни видимості, викликані змінами styleатрибутів (див. Рядок 59 тут ), тоді як зміни видимості можуть бути викликані також змінами в classатрибуті.
Ашраф Сабрі

Ти маєш рацію. Правильний вислів має бути e.attributeName! == 'style' && e.attributeName! == 'className'
Soul_Master

2

Після рішення Ніка Кравера, встановлення видимості елемента дозволяє йому отримати точні розміри. Я дуже часто використовував це рішення. Однак, маючи скинути стилі вручну, я виявив це громіздко, враховуючи, що змінюючи початкове розташування / відображення елемента в моєму css шляхом розвитку, я часто забуваю оновити відповідний код JavaScript. Наведений нижче код не скидає стилі на вимову, але видаляє стилі вбудованих даних, додані javascript:

$("#myDiv")
.css({
    position:   'absolute',
    visibility: 'hidden',
    display:    'block'
});

optionHeight = $("#myDiv").height();
optionWidth = $("#myDiv").width();

$("#myDiv").attr('style', '');

Єдине припущення тут полягає в тому, що не може бути інших стилів вбудованих файлів, інакше вони також будуть видалені. Перевага тут, однак, полягає в тому, що стилі елементів повертаються до того, яким вони були в таблиці стилів css. Як наслідок, ви можете записати це як функцію, коли елемент проходить через, а висота чи ширина повертаються.

Інше питання, яке я встановив щодо встановлення стилів inline через js, полягає в тому, що, працюючи з переходами через css3, ви змушені адаптувати ваги ваших правил стилю, щоб бути сильнішими за стиль вбудованого, що може часом бути неприємним.


1

За визначенням, елемент має висоту лише у тому випадку, коли його видно.

Просто цікаво: навіщо вам потрібна висота прихованого елемента?

Одна з альтернатив - ефективно приховати елемент, поставивши його позаду (використовуючи z-індекс) накладення якогось роду).


1
мені потрібна висота елемента, яка, схоже, ховається протягом часу, коли я хочу його висоти. я будую плагін, і мені потрібно зібрати деякі дані, як я його init
mkoryak

2
ще одна причина - центрування речей з javascript, які можуть бути ще не видно
Simon_Weaver

@cletus Якщо вам просто цікаво писати коментарі, це дуже часто буває при фронтальному кодуванні, щоб отримати розмір прихованого елемента.
Рантьєв

1

За моєї обставини, у мене також був прихований елемент, який не дав мені отримати значення висоти, але це був не сам елемент, а скоріше один з батьків ... тому я просто поставив чек на один із своїх плагінів, щоб побачити, чи це приховано, ще знайдіть найближчий прихований елемент. Ось приклад:

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

Насправді, це об'єднання відповідей Ніка, Григорія та Безвістості, щоб дати вам можливість вдосконалити метод Грегорі, але використовує обидва способи на випадок, якщо у атрибуті стилю, який ви хочете повернути, є щось, і шукає батьківський елемент.

Єдине, що я можу вирішити, - це те, що петля через батьків не є цілком ефективною.


1

Одне вирішення - створити батьківський поділ поза елементом, для якого потрібно отримати висоту, застосувати висоту '0' та приховати будь-який перелив. Далі візьміть висоту дочірнього елемента та видаліть властивість переповнення батьків.

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>


0

Ось сценарій, який я написав для обробки всіх методів виміру jQuery для прихованих елементів, навіть нащадків прихованих батьків. Зауважте, що, звичайно, є хіт продуктивності з використанням цього.

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

Відповідь безслідності виглядає ідеально для того, що мені потрібно, але не працює з jQuery, який я працюю: 1.3.2 Це призводить до того, що jQuery кидає this.clone (або щось дуже близько) - це не функція. У когось є ідеї, як це виправити?

0

Якщо ви вже відображали елемент на сторінці раніше, ви можете просто взяти висоту безпосередньо з елемента DOM (доступний в jQuery з .get (0)), оскільки він встановлюється навіть тоді, коли елемент прихований:

$('.hidden-element').get(0).height;

однакова для ширини:

$('.hidden-element').get(0).width;

(спасибі Skeets O'Reilly за виправлення)


Повертаєтьсяundefined
Джейк Вілсон

1
Напевно, це працює лише в тому випадку, якщо ви вже відображали елемент на сторінці раніше. Для елементів, які завжди були display='none', це не спрацює.
Skeets
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.