2009-09-24 4 views
101

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

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

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

ответ

89

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

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

Это своего рода хак, но, похоже, он работает нормально.

UPDATE

С тех пор я написал , которая охватывает эту тему. Метод, использованный выше, потенциально может быть проблематичным, поскольку вы возвращаете свойства 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)); 
+0

Это работало отлично, спасибо! – Martin

+1

Не заставит ли браузер дважды перерисовать страницу? Если это так, это субоптимальное решение. – marcusklaas

+0

@Tim Banks очень приятно! На самом деле я написал подобное расширение. То, что я заметил, очень странное поведение в ** Firefox **, width() возвращает 0, для вашего и моего плагина оба. И, кроме того, он никогда не влияет на заполнение. http://jsfiddle.net/67cgB/. У меня самое сложное время выяснить, что еще можно сделать, чтобы исправить это. –

38
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")); 
+0

грязный хороший трюк !!! Убедитесь, что клон имеет правильные свойства css (например, если размер шрифта исходного элемента равен 15, вы должны использовать clone.css («видимость», «скрытый»). Css («font-size», «15px»);) – alex

+13

Как раз отметить, это не сработает, если ваш элемент унаследовал свою ширину от любого родителя. Он просто наследует ширину тела, которая является неправильной. – Dean

+2

Я изменил 'clone.css (« видимость »,« скрытый »),' to 'clone.css ({« видимость »:« скрытый »,« отображение »:« таблица »});' который решает проблему, указанную by @Dean – isapir

3

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

8

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

Версия YUI для тех, кто в ней нуждается: https: //gist.github.com/samueljseay/13c2e69508563b2f0458 –

+0

Соответствует ли offsetTop для элемента, учитывая, что это клон, а не «реальный» элемент? Если вы используете $ this.offset(). Top? Также любопытно, для чего вы используете верхнюю/левую? Я использую только «ширину», но задаюсь вопросом, следует ли мне по каким-то причинам относиться к этим смещениям. – Terry

0

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

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

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

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

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

3

Я пытаюсь найти рабочую функцию для скрытого элемента, но я понимаю, что 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

демо: http://jsbin.com/ETiGIre/7

+4

** CSS очень сложный, чем все думают ** Это так ... – dgellow

1

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

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

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

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

, например:

// CSS

.module-контейнер .my-эль { границы: 60px сплошной черный цвет; }

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

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

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

0

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

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

Например:

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

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

Это не сработает, если на размер элементов влияет родительский контейнер или более сложный селектор CSS, основанный на иерархии компоновки. –

Смежные вопросы