17

我们在 JavaScript 中面临一个相当可怕的问题,我们似乎都没有能力解决:

我们如何在页面上不实际显示组件的情况下获取 DOM 元素的宽度和高度,包括子元素、整个盒子模型等?

请记住:我正在寻找建议。即使没有完全回答问题(或不完全符合指定参数)的答案也可能并且可能会有所帮助。

主要目标:我通过 Javascript 将 HTML 元素添加到页面中 - 来自数据库的具有大小和样式的 HTML 元素。问题是它们行为不端,通常是错误的对齐,由于填充/边距,一个元素大于另一个元素,因此我需要检查它们的实际大小以解决这些问题。

正如 BigMacAttack 在评论中所描述的那样,最终的应用程序将是一个“紧密结合的第 3 方 HTML 控件的马赛克”,这将是非常准确的。它需要看起来很像成熟的桌面应用程序,而 HTML 似乎对这个想法充满热情。不是我责备它。

无论如何,这里有一些示例代码:

JavaScript:

function exampleElement(caption, content) {
    this.caption = caption;
    this.content = content;
    this.rootElement = document.createElement("div");
}

exampleElement.prototype.constructElement = function() {
    var otherElement = document.createElement("p");
    this.rootElement.className = "exampleElement";
    this.rootElement.textContent = this.caption; 
    otherElement.className = "exampleP";
    otherElement.textContent = this.content;
    this.rootElement.appendChild(otherElement);
    /*I need to know size of the otherElement here*/
    /*here goes code adding stuff into rootElement*/
};

window.onload = function() {
    var ex = new exampleElement("Hello", "Here's text");
    ex.constructElement();
    document.body.appendChild(ex.rootElement);
};

CSS:

.exampleElement {
    padding: 5px;
    margin: 6px;
}

.exampleElement .exampleP {
    padding: 20px;
    margin: 6px;
}

一把小提琴

现在,我们需要我们的页面动态地对窗口大小和各个组件的内容做出反应,这就是为什么在显示对象之前能够获取对象的大小很重要的原因。同样重要的是,对象的创建明确分为三个阶段:

  • 通过新创建

  • DOM树的构造(constructElement)

  • 添加到文档中(直接添加到正文中或添加到另一个 DOM 树中)

在构建阶段了解各个元素的大小非常重要。

到目前为止,我们已经尝试通过 jQuery、DOM 宽度和高度属性来测量它,但这些都不适用于没有直接显示在页面上的 DOM 对象。我尝试的另一种方法是将对象添加到 document.body 中的几个函数,获取宽度和高度,然后立即将其删除 - 但是,由于我们的 CSS 文件非常具体,除非您插入整个 rootElement,否则这是不可靠的,这将是由于我们的组件变得相当复杂,因此性能和内存都非常糟糕。

我认为完全删除 .CSS 文件并直接通过 JS 定义样式的方法至少可以解决我们的部分困境,但必须有更好的方法。

开始赏金以获得更多想法和建议。只是射击人,即使答案不完全在问题的范围内(你会/你是怎么做的等等) - 我想要实现的目标是让我的 JS 生成的 HTML 控件正确组合在一起。

4

7 回答 7

10

如果您最初需要隐藏诸如手风琴、滑块和其他需要边界框信息才能正常工作的组件,您经常会遇到这种情况。

一个简单的技巧是添加 css 来隐藏相关内容的可见性并确保它不会闪烁或干扰您的布局。

它可以很简单:

{   visibility:hidden;
    position:absolute;
    left: -9999px;
}

然后在您准备好显示组件时将位置设置回静态或相对,并将可见性设置回可见。

小提琴就在这里,但它并不多:http: //jsfiddle.net/gwwar/ZqQtz/1/

于 2013-09-23T05:56:34.703 回答
5

使用 javascript 获取框模型 DOM 节点的渲染宽度和高度而不实际将其添加到要显示的 DOM 是不可能的。

为了证明这一点,让我们看一下 DOM 节点的渲染高度和宽度是如何在浏览器内部计算的。我将参考 WebKit 如何处理这个问题,因为它是最常用的布局引擎。

随着文档被解析,DOM 节点被添加到“DOM 树”中,Renderers为需要显示的 DOM 节点创建。这就是“渲染树”的构建方式。

以下是Dave Hyatt 在官方 WebKit 博客上题为“WebCore Rendering I – The Basics”的文章的节选:

“渲染器是通过 DOM 上的一个称为附件的过程创建的。在解析文档并添加 DOM 节点时, attach会在 DOM 节点上调用一个名为的方法来创建渲染器。

void attach()

attach方法计算 DOM 节点的样式信息。如果元素的 display CSS 属性设置为 none 或者如果节点是具有 display: none 设置的元素的后代,则不会创建渲染器。”

因此,为了提高效率,浏览器甚至不会为 display 设置为 none 的元素计算样式信息。因此,无法通过 javascript 访问该信息。但是,如果 display 属性设置为 none,则会发生以下情况:

“在附件期间,DOM 查询 CSS 以获取元素的样式信息。结果信息存储在一个名为 RenderStyle 的对象中……可以使用 style() 方法从 RenderObject 访问 RenderStyle……主要内容之一RenderObject 的主力子类是 RenderBox。这个子类表示遵循 CSS 框模型的对象。这些对象包括任何具有边框、填充、边距、宽度和高度的对象。

因此,如果您的用例允许您直接从浏览器通过 C/C++ 检索框模型渲染高度和宽度,并通过其他方式将其传递给您的 javascript 代码,那么您可以查询 RenderBox 的高度/宽度方法每个 DOM 元素的子类。这基本上就是 WebKit 开发人员工具获取此信息的方式。

于 2013-09-23T23:17:45.177 回答
1

你可以试试这个 jQuery 插件:https ://github.com/dreamerslab/jquery.actual

于 2013-09-24T03:20:16.243 回答
1

既然你要求相关的答案......

如果您的 DOM 元素不根据其内容动态调整大小,我建议使用以下工作流程。

虽然它可以让你的 DOM 结构有点臃肿,但使用“容器”对象通常会更好。这些对象将没有边框、填充或边距以保持其 DOM 尺寸可预测。然后你可以强迫孩子在它的容器范围内紧贴地展开。

您的容器对象将用于查询特定的尺寸和位置,因为没有额外的属性来解释尺寸失真。

http://jsfiddle.net/aywS6/

CSS

#container {
    position: absolute;
    margin:0px;
    padding:0px;
    width: 300px;
    height: 100px;
    background: #aaa;
    border: 0 none;
}

#subject {
    position: absolute;
    top: 0px;
    bottom: 0px;
    left: 0px;
    right: 0px;
    padding: 10px 20px;
    background: #aaf;
}

HTML

<div id="container">
    <div id="subject">
        contents...
    </div>
</div>
于 2013-09-24T15:51:38.657 回答
1

这里的问题是在页面上添加此元素之前无法获取元素大小。

在您的方法“constructElement”上,您将元素添加到根元素,但只是在加载时添加到页面。您的属性“rootElement”没有设置大小属性。

如果要操作这些属性,请重新考虑对象/方法的结构。

看我更新你的小提琴

$(function ()
{
    var ex = new exampleElement("Hello", "Here's text");
    ex.constructElement();
    document.body.appendChild(ex.rootElement);

    $("<span/>")
        .text(" => Width is " + $("div").width() + ", and Height is " + $("div").height())
        .appendTo($("div p"));
});
于 2013-09-25T14:23:49.710 回答
0

不知道这是否有帮助,但既然你要求任何答案:) 这就是我所拥有的。

我有一个类似的问题,我希望有一个很好的 jQuery 效果来根据它的内部内容将 HTML 容器调整为“自动”高度和宽度。这个想法仍然类似于一些人在这里已经提到的:你在“屏幕外”的某个地方有一个容器,你把你的东西放在那里,测量尺寸并删除它。所以这是我在这里找到的功能

jQuery.fn.animateAuto = function(prop, speed, callback) {
    var elem, height, width;
    return this.each(function(i, el) {
        el = jQuery(el), elem = el.clone().css({
            "height" : "auto",
            "width" : "auto"
        }).appendTo("body");
        height = elem.css("height"), width = elem.css("width"), elem.remove();

        if (prop === "height")
            el.animate({
                "height" : height
            }, speed, callback);
        else if (prop === "width")
            el.animate({
                "width" : width
            }, speed, callback);
        else if (prop === "both")
            el.animate({
                "width" : width,
                "height" : height
            }, speed, callback);
    });
};

这段代码比你需要的多一点,但你可能感兴趣的部分是:

elem = el.clone().css({
                "height" : "auto",
                "width" : "auto"
}).appendTo("body");
height = elem.css("height")
width = elem.css("width")

希望这可以帮助

于 2013-09-25T04:47:57.983 回答
0

如果主要问题是在将其放置到屏幕上之前无法获得大小,我建议创建一个允许 div 隐藏在页面背景下的类。这应该跨浏览器工作。

.exampleHidden{
    position: absolute;
    z-index: -1;
}

如果您将页面的 z-index 的主背景设置为 0,然后将隐藏类附加到您的新元素,它将把它放在背景下。假设它不大于​​您的背景,现在应该隐藏它,以便您在通过删除 .exampleHidden 类实际将其带回前台之前测量和设置高度和宽度。

于 2013-09-26T17:47:12.530 回答