2011-11-18 15 views
9

Piszę stronę internetową, która ma tabelę z wierszami, które otwierają się i zamykają. Początkowo niektóre wiersze są zamknięte (display: none) i chcę je zsunąć. Ustawienie wysokości i użycie overflow: hidden nie działa w wierszach tabeli, więc zmieniam wysokość div wewnątrz tabeli.Jak znaleźć wysokość elementu, który nie jest wyświetlany

To działa. Jedynym problemem jest to, że muszę znać wysokość div, zanim go otworzę, co wydaje się niemożliwe. Jednym z rozwiązań, jakie mogę sobie wyobrazić, jest załadowanie strony z pokazem wierszy, a następnie iteracja po nich, przechowywanie ich wysokości i ich ukrywanie. Nie podoba mi się to rozwiązanie, ponieważ strona ładowała się podczas ładowania.

Oto prosty, działający przykład mojego problemu.

<!DOCTYPE HTML> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<style type="text/css"> 
table, td {border: 1px solid black;} 
#lower_row {display: none;} 
#lower_div {overflow: hidden;} 
</style> 
<script type="text/javascript"> 
function toggleLower() { 
    lowerRow = document.getElementById("lower_row"); 
    lowerDiv = document.getElementById("lower_div"); 
    if (getStyle(lowerRow, "display") == "none") { 
     lowerRow.style.display = "table-row"; 
    } 
    else { 
     lowerRow.style.display = "none"; 
    } 
    showHeight(); 
} 
function showHeight() { 
    lowerDiv = document.getElementById("lower_div"); 
    document.getElementById("info").innerHTML = getStyle(lowerDiv, "height"); 
} 
// Return a style atribute of an element. 
// J/S Pro Techniques p136 
function getStyle(elem, name) { 
    if (elem.style[name]) { 
     return elem.style[name]; 
    } 
    else if (elem.currentStyle) { 
     return elem.currentStyle[name]; 
    } 
    else if (document.defaultView && document.defaultView.getComputedStyle) { 
     name = name.replace(/([A-Z])/g, "-$1"); 
     name = name.toLowerCase(); 
     s = document.defaultView.getComputedStyle(elem, ""); 
     return s && s.getPropertyValue(name); 
    } 
    else { 
     return null; 
    } 
} 
</script> 
</head> 

<body onload="showHeight()"> 
<p>The height the lower row is currently <span id="info"></span></p> 
<table> 
<tr id="upper_row" onclick="toggleLower()"><td><p>Click me to toggle the next row.</p></td></tr> 
<tr id="lower_row"><td><div id="lower_div"><p>Peekaboo!</p></div></td></tr> 
</table> 

</body> 
</html> 

Edit 1:

Jednym z proponowanych rozwiązań jest przenieść div poza stronę. Nie mogę tego zrobić, i myślę, że miałby złą wysokość, ponieważ jego wysokość zależy od szerokości stołu.

Pracuję nad rozwiązaniem użycia visibility:hidden, ale ma problemy. Nadal zajmuje niewielką ilość miejsca, a podana wysokość jest błędna. Oto przykład tego rozwiązania:

<!DOCTYPE HTML> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<style type="text/css"> 
table {width: 250px;} 
table, td {border: 1px solid black;} 
#lower_row {position: absolute; visibility: hidden} 
#lower_div {overflow: hidden;} 
</style> 
<script type="text/javascript"> 
function toggleLower() { 
    lowerRow = document.getElementById("lower_row"); 
    lowerDiv = document.getElementById("lower_div"); 
    if (getStyle(lowerRow, "visibility") == "hidden") { 
     lowerRow.style.visibility = "visible"; 
     lowerRow.style.position = "static"; 
    } 
    else { 
     lowerRow.style.visibility = "hidden"; 
     lowerRow.style.position = "absolute"; 
    } 
    showHeight(); 
} 
function showHeight() { 
    lowerDiv = document.getElementById("lower_div"); 
    document.getElementById("info").innerHTML = getStyle(lowerDiv, "height"); 
} 
// Return a style atribute of an element. 
// J/S Pro Techniques p136 
function getStyle(elem, name) { 
    if (elem.style[name]) { 
     return elem.style[name]; 
    } 
    else if (elem.currentStyle) { 
     return elem.currentStyle[name]; 
    } 
    else if (document.defaultView && document.defaultView.getComputedStyle) { 
     name = name.replace(/([A-Z])/g, "-$1"); 
     name = name.toLowerCase(); 
     s = document.defaultView.getComputedStyle(elem, ""); 
     return s && s.getPropertyValue(name); 
    } 
    else { 
     return null; 
    } 
} 
</script> 
</head> 

<body onload="showHeight()"> 
<p>The height the lower row is currently <span id="info"></span></p> 
<table> 
<tr id="upper_row" onclick="toggleLower()"><td><p>Click me to toggle the next row.</p></td></tr> 
<tr id="lower_row"><td><div id="lower_div"><p>This is some long text. This is some long text. This is some long text. This is some long text.</p></div></td></tr> 
</table> 

</body> 
</html> 

Edit 2: odpowiedź roztworze

Pawła jest rozwiązaniem na moje pytanie: jak znaleźć wysokość elementu, który nie jest wyświetlany. Jednak nie zadziałałby na mój problem. W mojej witrynie wysokość div zależy od jego szerokości, która zależy od szerokości td, która zależy od stanu pozostałych wierszy i szerokości tabeli, która zależy od szerokości strony. Oznacza to, że nawet jeśli dokonam wstępnej obliczenia wysokości, wartość będzie nieprawidłowa, gdy tylko ktoś rozwinie inny wiersz lub zmieni rozmiar okna. Kopiowanie tabeli i utrzymywanie wszystkich tych ograniczeń byłoby prawie niemożliwe.

Jednak znalazłem rozwiązanie. Gdy użytkownik kliknie, aby rozwinąć wiersz, moja witryna wykona następujące kroki w kolejności:

  1. Ustaw wartość div.style.height na 1px.
  2. Ustaw wiersz.style.display na wiersz tabeli.
  3. Zapisz wartość div.scrollHeight.
  4. Uruchom animację przewijania, zatrzymując się na div.scrollHeight.
  5. Po animacji ustaw div.style.height na auto.

div.scrollHeight podaje wysokość zawartości div, łącznie z jej przepełnieniem. Nie działa, gdy element div nie jest wyświetlany, ale nie stanowi to problemu dla mojej aplikacji. Oto przykład kodu w akcji. (Ponownie, nie uwzględniam kodu animacji przewijania, ponieważ byłaby zbyt długa.)

<!DOCTYPE HTML> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<style type="text/css"> 
table, td {border: 1px solid black;} 
#lower_row {display: none;} 
#lower_div {overflow: hidden;} 
</style> 
<script type="text/javascript"> 
function toggleLower() { 
    var lowerRow = document.getElementById("lower_row"); 
    var lowerDiv = document.getElementById("lower_div"); 
    if (getStyle(lowerRow, "display") == "none") { 
     lowerDiv.style.height = "0px"; 
     lowerRow.style.display = "table-row"; 
     showHeight(); 
     lowerDiv.style.height = "auto"; 
    } 
    else { 
     lowerDiv.style.height = "0px"; 
     showHeight(); 
     lowerRow.style.display = "none"; 
    } 
} 
function showHeight() { 
    var lowerDiv = document.getElementById("lower_div"); 
    document.getElementById("info").innerHTML = lowerDiv.scrollHeight; 
} 
// Return a style atribute of an element. 
// J/S Pro Techniques p136 
function getStyle(elem, name) { 
    if (elem.style[name]) { 
     return elem.style[name]; 
    } 
    else if (elem.currentStyle) { 
     return elem.currentStyle[name]; 
    } 
    else if (document.defaultView && document.defaultView.getComputedStyle) { 
     name = name.replace(/([A-Z])/g, "-$1"); 
     name = name.toLowerCase(); 
     s = document.defaultView.getComputedStyle(elem, ""); 
     return s && s.getPropertyValue(name); 
    } 
    else { 
     return null; 
    } 
} 
</script> 
</head> 

<body> 
<p>The height the lower row is currently <span id="info">...</span></p> 
<table> 
<tr id="upper_row" onclick="toggleLower()"><td><p>Click me to toggle the next row.</p></td></tr> 
<tr id="lower_row"><td><div id="lower_div"><p> 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
This is some long text. This is some long text. This is some long text. This is some long text. 
</p></div></td></tr> 
</table> 

</body> 
</html> 
+0

co wydaje się być problemem? Twój html działa poprawnie. kiedy klikam wiersz, rozwijany jest poniższy wiersz. –

+0

@vishal Aby zachować prostotę, mój przykład nie ma ruchomej animacji. Aby mieć animację ślizgową, muszę znać wysokość, zanim się rozszerzy. Jak pokazuje mój przykład, wysokość przed rozwinięciem jest "auto". – dln385

+0

@ dln385 zobacz moją aktualizację w moim poście –

Odpowiedz

14

Można kopiować div z treścią i umieścić go do ciała z pozycjonowania bezwzględnego top:-10000; left:-10000; tak będzie poza widocznym miejscu, to można obliczyć wysokość i usunąć klon z DOM.

UPDATE

Alternatywnie, w przypadku gdy dodać elementy w sposób dynamiczny, można ustawić go display:block, position:absolute i visibility:hidden - ale trzeba się upewnić, że nie zmieni stanowiska jakiegokolwiek elementu na stronie. visibility:hidden - nie pokaże element, ale obliczenia jego wymiary (w przeciwieństwie do display: none)

UPDATE

W danym przypadku rodzic ma wpływ na wymiary dziecka, więc trzeba sklonować elementu do "podobnego" rodzica, który znajduje się poza widocznym obszarem. Mówiąc „podobny” To znaczy powinien mieć takie same wymiary, ale w ogóle - style i wszystko co jest związane z jego rozmiar:

var wrapper = $('<div></div>').appendTo('body').css('display', 'block').css('position', 'absolute').css('top', -10000).css('left', -10000).css('width', $('table').css('width')); 
var clone = $('#lower_div').clone().appendTo(wrapper);  
document.getElementById("info").innerHTML = clone.height(); 

Tu pracuje jsfiddle dla Ciebie.

+0

Czy nie pokazywałabym krótko przewijania na stronach, które nie są ukryte? Co powiesz na wyrzucenie go w elemencie iframe o wartości 'width: 0; wysokość: 0; '? – Sorpigal

+0

Nie spowoduje, że nie będą wyświetlane żadne paski przewijania, ponieważ będzie to poza przepływem strony. Przy okazji, nie zapomnij zastosować tych samych stylów do elementu div, aby kopia miała dokładnie taką samą wysokość. iframe może działać, ale jest to rozwiązanie cięższe/wolniejsze. –

+0

@Paul Nie mogę uruchomić żadnego rozwiązania. Zobacz moją edycję. – dln385

Powiązane problemy