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

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

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

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

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

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

如您所见,如果脚注仅包含文本,则一切都很完美。 但如果它们也包含图像,则旁注开始重叠。 我相信这是因为我使用.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答案 。

那时你开始计算元素了吗?

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

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

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

更多信息:

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

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

不幸的是, onload只会触发:

如果您可以提前预测图像尺寸,那将是理想的。 由于您的用例不允许,您可以根据脚注的内容绑定到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();