为啥通过 AJAX 无限滚动加载的内容的高度在加载后没有正确测量?

Posted

技术标签:

【中文标题】为啥通过 AJAX 无限滚动加载的内容的高度在加载后没有正确测量?【英文标题】:Why is the height of content loaded through AJAX infinity scroll not measured correctly after loading?为什么通过 AJAX 无限滚动加载的内容的高度在加载后没有正确测量? 【发布时间】:2016-03-28 08:47:22 【问题描述】:

我正在使用 无限滚动(通过 AJAX 实现)将由图片或视频组成的帖子加载到我网站的主 div 中。该系统的工作方式与任何流行的 meme 网站非常相似。

问题:每个帖子的左侧都有一个正文部分,右侧有一个社交按钮容器。我希望社交按钮容器在用户滚动时与帖子正文一起移动,并停在父 div 的底部,以便他们在到达帖子底部时可以喜欢它。问题是 一些 通过我的 AJAX 滚动功能加载的帖子似乎没有正确计算父母的高度,并且当浏览器窗口到达他们。 Here is a visual illustration 所需的行为。

实现:我无法编译一个可以工作的 jsFiddle,它可以模拟 AJAX 请求加载图像和视频以及“滚动”调用的行为。这是我的实现和调试尝试:

每篇文章的结构如下:

<div class="article-container">
   <div class="article-body-left"><img src="..."></div>
   <div class="social-buttons-right">
      <div class="facebook-button">...</div>
   </div>
</div>

每个 AJAX 请求完成后,我尝试使用 on 'scroll' 来确定每个社交按钮容器的位置,并在用户使用 ajaxComplete() 滚动时修改它们:

$(document).ajaxComplete(function() 
  bind_sticky_boxes();
); 

function bind_sticky_boxes() 
  $(window).on('scroll', function() 
    $('.social-buttons-right').not('.following').each( function()  
        var element = $(this).addClass('following'),
        originalY = element.offset().top,   
        parent_offset = element.parent().offset().top,
        parent_height = element.parent().height(),
        element_height = element.height(),
        destination = originalY+parent_height-element.height() -10;

          $(window).on('scroll', function(event) 
              var scrollTop = $(window).scrollTop();
              if (scrollTop > originalY - 10)
                 element.css('position','absolute');
                 element.css('top',(scrollTop - parent_offset + 10) + 'px');
                 element.css('right', '0px');
                 if (scrollTop > (destination -10 ) ) 
                      element.css('top',parent_height-element_height);
                      element.css('right', '0px'); 
                      element.css('bottom', '0px');
                 
               else 
                 element.css('position','relative');
                 element.css('top','initial');
                 element.css('left', 'initial');
                 element.css('right','initial');
                 element.css('bottom', 'initial');
               
          );
    );
    );

调试和注意事项:滚动功能在第一次 AJAX 请求后工作正常,但之后由于某些 .social-buttons-right 不跟随而有些中断沿着文章正文或在站点滚动期间直接跳到父 div 的底部。

当我检查行为异常的元素时,我发现它们都有“.following”,这意味着滚动功能已经找到它们,但它们也得到了 bind_sticky_boxes 给它们的 css 属性的错误组合。

这让我相信它与图像加载期间的高度计算有关,所以我使用 requestanimationframe() 稍等片刻,然后 setTimeout(function()..,2000) 触发滚动绑定更晚。这些都没有真正解决问题(后者无论如何都不是解决方案。)我也尝试过早一点触发 AJAX 请求,但由于某种原因,这似乎产生了更糟糕的效果。

更新:我现在确信问题与父身高计算有关。我将 css 属性交换为具有相同属性的唯一类,并注意到行为不端元素的类更改几乎总是发生在父 div 的开头,我认为这强烈表明它的高度在之后没有正确计算将其附加到主 div。

关于我的无限卷轴。我不包括整个 AJAX,因为我认为它与问题没有严格的关系。但我以这种方式将内容附加到主 div:

success: function(response)
            if ( max_page >= paged)
                $('#page').append(response.content);
             else
                has_content = false;
            
            loading = false;
          

页面加载完成后,我开始无限滚动。当用户到达 ID load-more-posts 的元素时触发 AJAX 请求,该元素位于主包装器下方。

$(window).on('load',function()
 $(window).on('scroll', function() 
      var element_position = $('#load-more-posts').offset().top + $('#load-more-posts').outerHeight() - window.innerHeight;
      var y_scroll_pos = $(window).scrollTop();
      if( ( y_scroll_pos >= element_position ) && !loading) 
          paged++;
          load_more_posts();
      
  );    

);

【问题讨论】:

@Mayank 我什至无法正确布局。 jsFiddle 增加了某种我无法摆脱的边距。我希望 .post-body 留在左边, .post-social 放在右边,但 .post-body 中有一个我无法删除的边距。两者都在 .post-container 内......不知道为什么边距是那里有jsfiddle.net/hu0om6d3/4 我没有看到您的 AJAX 存在问题,但我发现您的 CSS 存在问题。你能发布一张图片来展示你想要的样子吗? @LGSon 抱歉,我要去吃圣诞晚餐了。明天会发布更多信息。我将补充一点,我将 css 放在单独的类中并交换它们,这样它们就不会混合,这对于第一个 ajax 请求很有效。只是在我在以下请求中附加新帖子后,父级高度似乎计算得很差,好像里面没有图像,社交按钮容器只是跳到父级的末尾。因此,为什么我猜它与图像加载有关。明天我会更详细地改进这个问题。 检查了您的图片并重新阅读了您的问题。在我看来,当计算发生时,元素引用可能指向错误的帖子,就像你说它要么停留在顶部要么跳到底部。如果它引用了一个高于或低于视图的元素,那将是预期的行为。这可能有助于调试,如果您需要进一步的帮助,则需要一个有效的 sn-p 来查看发生了什么。 有了这些知识,您现在知道如何解决它了,对吧? .. 无论如何,这里有一篇文章可能有助于了解何时加载图像:***.com/questions/821516/… 【参考方案1】:

问题是目前各种高度/位置属性的计算绑定到滚动事件,该事件可能在通过 AJAX 附加的图像加载之前触发,因此计算不正确。为了解决这个问题,我必须将它绑定到加载事件,以确保图像可以使用。

$('.article-body-left img').one('load', function() 
    var element = $(this).parent().parent().find('.social-buttons-right'),
    originalY = element.offset().top,
    parent_offset = element.parent().offset().top,
    parent_height = element.parent().height(),
    element_height = element.height(),
    destination = parent_offset+parent_height-element.height() -10;
    //alert("Element offset: "+originalY+"\nParent offset: "+parent_offset+"\nParent height: "+parent_height+"\nElement height: "+element_height+"\nDestination: "+destination);
      $(window).on('scroll', function(event) 
          var scrollTop = $(window).scrollTop();
          if (scrollTop > originalY - 10)
             element.removeClass('above').removeClass('below').addClass('along');
             element.css('top',(parseInt(scrollTop - parent_offset + 10)) + 'px');
             if (scrollTop > (destination -10 ) ) 
                  element.removeClass('above').removeClass('along').addClass('below');
                  element.css('top','');
             
           else 
            element.removeClass('below').removeClass('along').addClass('above');
            element.css('top','');
          
      );
).each(function() 
  if(this.complete) $(this).load();
);

CSS:

.along
   position: absolute;
   right : 0px;


.below
    position: absolute;
    right: 0px;
    bottom: 0px;

.above
  position: relative;

【讨论】:

以上是关于为啥通过 AJAX 无限滚动加载的内容的高度在加载后没有正确测量?的主要内容,如果未能解决你的问题,请参考以下文章

js 实现无限加载分页(适合移动端)

AJAX 功能不能通过滚动工作

无限滚动加载解决方案之虚拟滚动(下)

防止重复无限滚动ajax加载器

下拉加载更多内容(滚动加载)

JQ-滚动条下拉无限的加载数据