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

时间:2011-06-30 06:33:54

标签: javascript jquery

我对JavaScript / jQuery /编程一般都是新手,所以如果我遇到痛苦的天真,请耐心等待。

我编写了一个脚本,将Tumblr博客上的脚注转换为“旁注”。在大多数情况下,它的效果非常好。你可以see examples on my blog

我这样做是通过将脚注的innerHTML附加到空div,然后用CSS(display: none)隐藏原始脚注。我根本不想改变帖子的标记。我的想法是,我可以删除脚本和旁注,还原或“降级”回脚注。

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

脚本非常简单。基本算术。为了避免重叠元素,我计算从页面顶部到前一个元素底部的偏移量。如果它大于参考链接的偏移量(以及容器的偏移量),则元素向下移动。

正如您所看到的,如果脚注只包含文本,那么一切都很完美。但如果它们也包含图像,则旁注开始重叠。我相信这是因为我使用.outerHeight()来获取元素的高度,但是如果图像尚未加载,则返回错误的值。您可以在one of my test pages上看到我正在谈论的内容示例。

我认为我已将问题与以下功能隔离开来。

我认为如果我使用.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;
    }); 
}

4 个答案:

答案 0 :(得分:4)

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

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

    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),它们最初有上限,伪常量是有时在全部大写中完成。所以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. 由于我们的一个终止条件是异步,我使它们异步,因此调用者看到相同的东西(异步结果),无论是否有图像到是否注意,如果我们不需要等待任何事情,请通过done致电setTimeout
    8. 上面没有注意图像加载错误(通过error),它可能应该;如果图像加载失败,它将永远不会发出回调。
    9. 您可能会发现this other SO answer关于观看图片加载有用。

答案 1 :(得分:0)

您从哪个角度开始计算元素?

我建议等待整个页面加载bevor你计算任何东西。

您可以使用Jquery函数准备好:

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

此处提供更多信息:

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

答案 2 :(得分:0)

首先,祝贺一个非常优雅的插件!

不幸的是,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);

答案 3 :(得分:-1)

尝试以下

  

$(选择器).height();