在内容完全加载后测量元素的高度

Measure height of element after content is fully loaded

本文关键字:测量 元素 高度 加载      更新时间:2023-09-26

我对JavaScript/jQuery/编程完全陌生,所以如果我给人的印象是天真的,请耐心等待。

我写了一个脚本,将汤博乐博客上的脚注转换为"旁注"。在大多数情况下,它运行得很好。你可以在我的博客上看到例子。

为此,我将脚注的innerHTML附加到一个空div中,然后用CSS(display: none)隐藏原始脚注。我根本不想更改帖子的标记。我的想法是,我可以删除脚本和旁注,恢复或"降级"回脚注。

旁注相对于其容器是绝对定位的,它们的位置取决于几个因素:前一个旁注的位置、引用链接在文本中的位置以及容器的位置。理想情况下,旁注应该与文本中的引用链接出现在相同的垂直偏移处,但如果前面的元素挡住了去路,它会向下移动以避免重叠。

剧本很简单。基本算术。为了避免元素重叠,我计算了从页面顶部到前一个元素底部的偏移量。如果它大于引用链接的偏移量(和容器的偏移量),则元素向下移动。

正如你所看到的,如果脚注只包含文本,一切都会完美地进行。但是,如果它们也包含图像,侧注就会开始重叠。我相信这是因为我使用.outerHeight()来获取元素的高度,但如果图像还没有加载,它会返回错误的值。你可以在我的一个测试页面上看到我所说的一个例子。

我想我已经将问题隔离到下面的函数中了。

我想如果我使用.load,它会等待元素的内容加载后再执行代码。但这似乎并没有发生。

请告诉我我可能做错了什么。我很确定脚本的问题包含在下面的代码中,但如果你认为这看起来不错,我也可以发布脚本的其余部分。或者你可以在http://resources.contentioninvain.com/scripts/FootnotesToSidenotes.js上查看(对不起,我是新用户,所以我不能发布两个以上的链接,哈哈)。

提前感谢您的任何建议。这是我第一次发布问题,但我发现这个网站在过去真的很有用。除了修修补补,这是我第一次尝试从头开始写剧本(我有点自豪,我在没有帮助的情况下走到了这一步,哈哈)。

// GetBottomOffset gets the vertical offset to the bottom of an element
// It adds the element's vertical offset and its height:
function GetBottomOffset(Element) {
    $(Element).load(function() {
        var ElementTop = Element.offset().top; // Vert offset of element
        var ElementHeight = Element.outerHeight(true); // Height of element
        // Offset to bottom of element
        var ElementBottom = ElementTop + ElementHeight;
        // Returns ElementBottom
        return ElementBottom;
    }); 
}

我认为有三个不相关的问题:

  1. 我认为你也必须单独观察要加载的图像,并且只有在所有内容都加载时才进行计算
  2. 如果等待事件首先发生,则不能从函数返回值,因为函数在事件发生之前已经返回。您需要使用回调
  3. 在挂接load事件之前,您必须允许已经加载的映像

例如:

function watchForBottomDimension(element, callback) {
    var $element, images, loaded;
    // Get a jQuery wrapper for `element`
    $element = $(element);
    // Find the images within it that aren't loaded yet
    images = $element.find("img").filter(function(index, img) {
        return !img.complete;
    });
    // Find any?
    if (images.length === 0) {
        // No, we're done -- call the callback asynchronously for
        // consistency with the case below where we have to wait
        setTimeout(done, 0);
    }
    else {
        // We're waiting for some images, do that
        loaded = 0;
        images.load(function() {
            // One of them loaded; was it the last one?
            if (++loaded === images.length) {
                // Yup, we're done
                done();
            }
        }); 
    }
    // Handle completion
    function done() {
        var top, height, bottom;
        top = $element.offset().top; // Vert offset of element
        height = $element.outerHeight(true); // Height of element
        // Offset to bottom of element
        bottom = top + height;
        // Call the callback with the value
        callback(element, bottom);
    }
}

一些注意事项:

  1. 这是偏离主题的,但这可能是你在上面会注意到的第一件事,所以:我已经更改了事物的名称。在JavaScript中,最常见的惯例是,除了构造函数(主要用new调用的函数,如Date)和伪常量(有时用ALL CAPS完成)之外,所有函数都使用小写字母。所以element而不是ElementdoSomething而不是DoSomething等等
  2. 我正在检查图像是否通过HTMLImageElement#complete加载。然而,根据该规范,存在竞争条件,因为completed可能在我们检查它和挂接load事件之间发生变化(直到我去寻找参考,我才意识到这一点;令人惊讶),因此可能需要一种更稳健的方法
  3. 原始代码的一部分假设Element是一个jQuery实例,其他部分则将其传递到$中,就好像它不是一样。在上面的文章中,我假设它是一个原始DOM元素;如果它是一个jQuery实例,只需删除$element = $(element)位并使用element而不是$element
  4. 请注意,我的watchForBottomDimension接受一个名为callback的参数,它应该是一个函数。稍后,它用维度调用该函数(同时传递回元素,必须用于引用)
  5. 我去掉了观察元素本身的部分;应该没有必要(除非元素是图像)。但我添加了观看其中的图像—特别是还不是loaded的图像
  6. 有两种终止条件:A)没有我们需要等待的图像,B)有。所以我们需要在两个地方执行done逻辑,所以我把它放在一个嵌套函数中(因为其中一个地方在load事件处理程序中)
  7. 由于我们的终止条件之一是异步,因此我使它们异步,因此无论是否有图像要观看,调用者都会看到相同的东西(异步结果),在我们不必等待任何东西的情况下,通过setTimeout调用done
  8. 上面没有注意到图像加载错误(通过error),这可能是应该的;如果图像加载失败,它将永远不会发出回调

你可能会发现另一个关于观看图像负载的SO答案很有帮助。

您从哪一点开始计算元素?

我建议等待完整的页面加载,然后再计算任何内容。

您可以使用Jquery函数ready:

$(document).ready(function(){...}); 

更多信息请点击此处:

http://api.jquery.com/ready/

首先,祝贺您获得了一个非常优雅的插件!

不幸的是,onload只在上启动

  • <body>
  • <link><script>
  • <frame><frameset><iframe>
  • <img>

如果你能提前预测图像的尺寸,那将是理想的。由于您的用例不允许这样做,您可以根据脚注的内容绑定到onload事件:

var resize = function() {
  // within this handler, `this` will refer to the img tag.
  var container = $(this).closest('.sidenote');
  // ... resize calculation ...
}
// bind images in the sidenote to the resize handler
$('img', sidenote).load(resize);

尝试以下

$(选择器).height();