【问题标题】:How to find the height of an element that is not displayed如何查找未显示的元素的高度
【发布时间】:2021-07-25 12:35:22
【问题描述】:

我正在编写一个网页,其中有一个表格,其中的行可以滑动打开和关闭。最初,有些行是关闭的 (display: none),我希望它们滑动打开。设置高度和使用overflow: hidden 不适用于表格行,所以我要更改表格内 div 的高度。

这行得通。唯一的问题是我需要在滑动打开之前知道 div 的高度,这似乎是不可能的。我能想到的一种解决方案是加载显示行的页面,然后遍历它们,存储它们的高度并隐藏它们。我不喜欢这个解决方案,因为加载时页面会跳来跳去。

这是我的问题的一个简单、可运行的示例。

<!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>

编辑 1:

一种建议的解决方案是将 div 移出页面。我无法让它工作,而且我认为它的高度会错误,因为它的高度取决于桌子的宽度。

我正在研究使用visibility:hidden 的解决方案,但它有问题。它仍然占用少量空间,并且报告的高度是错误的。这是该解决方案的一个示例:

<!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>

编辑 2:解决方案

Paul 的回答是我的问题的解决方案:如何找到未显示的元素的高度。但是,它不适用于我的问题。在我的网站上,div 的高度取决于它的宽度,它取决于 td 的宽度,它取决于其他行的状态和表格的宽度,它取决于页面的宽度。这意味着,即使我预先计算了高度,只要有人扩展另一行或更改窗口大小,该值也会出错。此外,复制表格并保留所有这些约束几乎是不可能的。

但是,我找到了解决方案。当用户点击展开一行时,我的网站会按顺序执行以下步骤:

  1. 将 div.style.height 设置为 1px。
  2. 将 row.style.display 设置为 table-row。
  3. 存储 div.scrollHeight 的值。
  4. 运行滚动动画,在 div.scrollHeight 处停止。
  5. 动画结束后,将 div.style.height 设置为 auto。

div.scrollHeight 给出了 div 内容的高度,包括它的溢出。不显示 div 时它不起作用,但这对我的应用程序来说不是问题。这是实际代码的示例。 (同样,我没有包含滚动动画的代码,因为它太长了。)

<!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>

【问题讨论】:

  • 似乎是什么问题?您的 html 工作正常。当我单击该行时,下面的行会展开。
  • @vishal 为了简单起见,我的示例没有滑动动画。为了有一个滑动动画,我需要知道它展开之前的高度。正如我的示例所示,它展开之前的高度是“自动”。
  • @dln385 请在我的帖子中查看我的更新

标签: javascript html css


【解决方案1】:

您可以将带有内容的 div 复制并以绝对定位 top:-10000; left:-10000; 将其放在 body 上,使其超出可见区域,然后您可以计算高度并从 DOM 中删除克隆。

更新

或者,如果您以动态方式添加元素,您可以将其设置为 display:blockposition:absolutevisibility:hidden - 但您必须确保它不会改变任何元素在页。 visibility:hidden - 不会显示元素,但会计算它的尺寸(与 display: none 相比)

更新

在您的特定情况下,您的父母对孩子的尺寸有影响,因此您需要将您的元素克隆到可见区域之外的“相似”父母。通过说“相似”,我的意思是它应该具有相同的尺寸,但总的来说 - 样式以及与其大小相关的所有内容:

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

这是jsfiddle 为您工作。

【讨论】:

  • 不会为没有溢出隐藏的页面短暂显示滚动条吗?将其放入width: 0; height: 0; 的 iframe 中怎么样?
  • 不,它不会显示任何滚动条,因为它会超出页面流。顺便说一句,不要忘记对 div 应用相同的样式,因此副本将具有完全相同的高度。 iframe 可能有效,但它是较重/较慢的解决方案。
  • @Paul 我无法让任何一种解决方案发挥作用。请查看我的编辑。
【解决方案2】:

您可以通过显示元素、捕获高度,然后在浏览器重新绘制屏幕之前重新隐藏元素来完成此操作。因此,用户永远不会注意到发生的任何事情。我为用于滑动具有动态高度的打开和关闭元素的封装执行此操作:

https://github.com/alexmacarthur/slide-element/blob/master/src/index.ts

在超级简单的代码中:

<div id="element" style="display: none;">hello</div>

<script>
   const element = document.getElementById('element');
   
   element.style.display = "";
   const elementHeight = element.clientHeight;
   element.style.display = "none";

   console.log(elementHeight); // whatever the rendered height is.
</script>

【讨论】:

    猜你喜欢
    • 2013-12-06
    • 2014-04-18
    • 1970-01-01
    • 2019-09-03
    • 1970-01-01
    • 2021-09-18
    • 2011-02-12
    • 2014-01-03
    • 2019-02-28
    相关资源
    最近更新 更多