内容完全加载后测量元素的高度 [英] Measure height of element after content is fully loaded

查看:96
本文介绍了内容完全加载后测量元素的高度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am completely new to JavaScript/jQuery/programming in general, so please bear with me if I come across as painfully naive.

我写了一个脚本将Tumblr博客上的脚注转换为旁注。在大多数情况下,它的效果非常好。您可以查看我博客上的示例

I've written a script that converts the footnotes on a Tumblr blog to "sidenotes." It works pretty well, for the most part. You can see examples on my blog.

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

I do this by appending the innerHTML of the footnotes to an empty div, then hiding the original footnotes with CSS (display: none). I don't want to alter the markup of the posts at all. The idea is that I can remove the script and sidenotes revert or "degrade" back to footnotes.

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

The sidenotes are absolutely positioned relative to their container, and their position depends on several factors: the position of the preceding sidenote, the position of the reference link in the text, and the position of the container. Ideally, the sidenote should appear at the same vertical offset as the reference link in the text, but if the preceding element is in the way, it shifts down to avoid overlapping.

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

The script is pretty simple. Basic arithmetic. To avoid overlapping elements, I calculate the offset from the top of the page to the bottom of the preceding element. If its larger than the offset of the reference link (and the offset of the container), the element shifts down.

正如您所看到的,如果脚注一切正常只包含文字。但如果它们也包含图像,则旁注开始重叠。我相信这是因为我使用.outerHeight()来获取元素的高度,但是如果图像尚未加载,则返回错误的值。你可以在我的一个测试页面上看到我正在谈论的一个例子。

As you can see, everything works perfectly if the footnotes only contain text. But if they contain images, too, the sidenotes start to overlap. I believe it's because I'm using .outerHeight() to get the height of the element, but if the image hasn't loaded yet, it returns the wrong value. You can see an example of what I'm talking about on one of my test pages.

我认为我已将问题与以下函数隔离开来。

I think I've isolated the problem to the function below.

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

I thought that if I used .load, it would wait for the element's content to load before executing the code. But that doesn't seem to be happening.

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

Please tell me what I might be doing wrong. I'm pretty sure the script's problem is contained in the code below, but if you think this looks fine, I can post the rest of the script as well. Or you can view it at http://resources.contentioninvain.com/scripts/FootnotesToSidenotes.js (Sorry, I'm a new user so I can't post more than two links, haha).

提前感谢任何建议。这是我第一次发布问题,但我发现这个网站过去非常有用。除了修补之外,这是我第一次尝试从头开始编写脚本(我很自豪我没有帮助就得到了这么多,哈哈)。

Thanks in advance for any suggestions. This is the first time I've posted a question, but I've found this site really useful in the past. Aside from tinkering, this is the first time I've tried to write a script from scratch (I'm kind of proud that I've gotten this far without help, haha).

// 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;
    }); 
}


推荐答案

我认为有三个无关问题:

I think there are three unrelated issues:


  1. 我认为您必须单独观看要加载的图像,并且只在加载所有内容时进行计算。

  2. 如果等待事件先发生,你不能返回函数中的值,因为在事件发生之前函数已经返回。您需要使用回调。

  3. 在挂钩加载之前,您必须允许加载图像
  4. code> event。
  1. I think you'll have to watch individually for the images to load as well, and only do the calculation when everything is loaded.
  2. You can't return the value from the function if you wait for an event to occur first, because the function will have already returned before the event occurs. You'll need to use a callback.
  3. You have to allow for the image already being loaded before you hook the load event.

例如:

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中完成。所以元素而不是元素 doSomething 而不是 DoSomething 等。

  2. 我正在检查图像是否通过 HTMLImageElement #complete 。但是,根据那个规范,有一个竞争条件,因为已完成可能会在我们检查它和挂钩加载
  3. 原始代码的一部分是假设元素是一个jQuery实例,其他部分将它传递到 $ ,就好像它不是。在上面我假设它是一个原始的DOM元素;如果它是一个jQuery实例,只需删除 $ element = $(element)位并使用元素而不是 $ element

  4. 请注意,我的 watchForBottomDimension 接受一个名为<$ c的参数$ c>回调,这应该是一个函数。之后,它调用具有维度的函数(也传回元素,必须作为参考)。

  5. 我删除了观察元素本身的位;它不应该是必要的(除非元素是图像)。但我添加了观看其中的图像 —具体来说,还没有(还)加载的图像

  6. 有两种终止条件:A)没有图像我们需要等待,而且B)有。所以我们需要在两个地方执行 done 逻辑,所以我把它放在一个嵌套函数中(因为其中一个地方在中加载事件处理程序)。

  7. 由于我们的一个终止条件是异步,我让它们都是异步的通过完成通过 setTimeout 如果我们不需要等待任何事情。

  8. 上面没有注意图像加载错误(通过 错误 ),它可能应该;如果图像加载失败,它将永远不会发出回调。

  1. This is off-topic, but it's probably the first thing you'll notice in the above, so: I've changed the names of things. In JavaScript, the overwhelming convention is to use an initial lower case letter for everything except constructor functions (functions you primarily call with new, like Date), which are initially capped, and pseudo-constants which are sometimes done in ALL CAPS. So element rather than Element, doSomething rather than DoSomething, etc.
  2. I'm checking whether the images are loaded via HTMLImageElement#complete. According to that spec, though, there's a race condition because completed could change between when we check it and when we hook the load event (I didn't realize that until I went looking for the reference; surprising), so a more robust approach may be required.
  3. Part of your original code is assuming Element is a jQuery instance, other parts are passing it into $ as though it weren't. In the above I've assumed it's a raw DOM element; if it's a jQuery instance instead, just remove the $element = $(element) bit and use element instead of $element.
  4. Note that my watchForBottomDimension accepts a parameter called callback, which is expected to be a function. Later, it calls that function with the dimension (also passing back the element, must for reference).
  5. I removed the bit watching the element itself; it shouldn't be necessary (unless the element is an image). But I added watching for images within it — specifically, the images that aren't (yet) loaded.
  6. There are two termination conditions: A) There were no images that we needed to wait for, and B) There were. So we need to do our done logic in two places, so I put it in a nested function (since one of those places is in a load event handler).
  7. Since one of our termination conditions is asynchronous, I made them both asynchronous so the caller sees the same thing (an asynchronous result) regardless of whether there were images to watch or not, by calling done via setTimeout in the case where we don't have to wait for anything.
  8. The above doesn't watch for image load errors (via error), which it probably should; if an image load fails, it'll never issue the callback.

你可能会发现这个其他的答案关于观看图片加载有帮助。

You may find this other SO answer about watching for image loads helpful.

这篇关于内容完全加载后测量元素的高度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆