【问题标题】:When appending items dynamically, masonry does not layout them out动态附加项目时,砌体不会将它们布置出来
【发布时间】:2018-04-25 14:18:27
【问题描述】:

我正在使用 Masonry JavaScript 网格布局库 https://masonry.desandro.com/。使用 Angular *ngfor 直接从 DOM 将新项目附加到网格时遇到问题,它遍历数组,如下所示:

<div class="grid">
  <div class="grid-item grid-item--height{{i}}" *ngFor="let i of array">
   {{i}}
  </div>
</div>

因为我没有使用“附加砌体方法”附加它们,所以砌体不会将它们布置出来。每次用户向下滚动时,该数组都会获取新元素。于是调用了一个 JavaScript 方法:

onScrollDown() {
 // add another 20 items
 this.sum += 20;
 for (let i = start; i < this.sum; ++i) {
     this.array.push(i);  }
 }

当数组获得更多元素时,它会自动创建新的 html 项。所以我需要在创建新项目后再次找到砌体布局的方式。在将元素添加到 OnScrollMethod 中的数组后,我尝试调用 $grid.masonry('layout') 但它不起作用。 我也在尝试 $('.grid').masonry('reloadItems') ,但是调用此方法时新项目与以前的项目重叠。

我将不胜感激。

更新:

我正在使用我的角度初始化组件方法初始化砌体,如下所示:

  ngOnInit() {
  this.$grid = jQuery('.grid').masonry({
    // options
    itemSelector: '.grid-item',
    columnWidth: 384,
    gutter: 24
  });

【问题讨论】:

    标签: javascript html angular jquery-masonry masonry


    【解决方案1】:

    我在 Vue.js 中使用了 masonry-layout 并且遇到了同样的问题。解决我的问题的方法是:

    onScrollDown() {
      // ...
      // after add another 20 items
      this.msnry.reloadItems();
      this.msnry.layout();
     }
    

    this.msnry 是我的砌体布局实例。

    【讨论】:

      【解决方案2】:

      更新

      你可以试试reloadItems。如果您正在加载图片,请使用imagesLoaded.js 以避免重叠:

      ngOnInit() {
      this.$grid = jQuery('.grid').imagesLoaded( function() {
      jQuery('.grid').masonry({
      // options
      itemSelector: '.grid-item',
      columnWidth: 384,
      gutter: 24
      });
      });
      
      
      onScrollDown() {
      // add another 20 items
      this.sum += 20;
      for (let i = start; i < this.sum; ++i) {
       this.array.push(i);  }
      jQuery('.grid').imagesLoaded( function() {
      jQuery('.grid').masonry('reloadItems');
      });
       }
      

      【讨论】:

      • 感谢@Macsupport。我尝试了 $('.grid').masonry('reloadItems') 并且它似乎在运行砌体,但现在它正在将新项目覆盖在以前的项目之上。我正在使用我的角度初始化组件方法初始化砌体。请参阅问题中的更新。知道如何阻止这种重叠行为吗?
      • 如果是加载图片,则需要使用imagesloaded.js避免重叠。
      【解决方案3】:

      自从我不得不这样做已经很多年了,但基本上:

      Masonry 运行大量 JS,以便为您正在创建的元素找出最佳的装箱方式。 这意味着它会在您所在区域内的每张“卡片”上硬编码大量样式信息,并在计算后对其进行设置。 如果您使用 Masonry 向该视图添加新的“卡片”,那么它将继续更新视图,并更改这些卡片的布局和大小。 如果您不使用之前的 Masonry 实例(您使用的是元素,而不是 Masonry 对象),那么 Masonry 就无法跟踪更改。此时,您要么必须将它们添加到 DOM,然后通过 addItems 将它们添加到对象,然后调用 layout()(或 masonry())... 或者您必须重新包装 DOM 元素再次砌体,现在元素已更新。

      这可能已经改变,但我对此表示怀疑。

      我猜你可以通过编写 angular 指令来做一些事情,但是实现这一点的廉价而愉快的方法是保存组件元素的实例(或控制器绑定到的元素......无论如何) ,并保存对您制作的 Masonry 视图的引用,并在更新时添加所有项目,然后再次调用布局... ...或者只是,在每次渲染时,使用您的根元素创建一个新的 Masonry 视图。 PS:确保一次加载很多新元素,因为如果你一次只加载 3 个它会很乱...... ...另外,请确保您在元素中预加载图像,因为如果图像随后加载,您的 Masonry 布局将会变得非常非常混乱。

      【讨论】:

      • 感谢@Norguard。这种方法似乎有点复杂。让我看看我能不能消化它并尝试一下。
      • @D.B 这很复杂,因为无论您是否知道,您都有很多事情要做。 Angular 的工作方式和 Masonry 的工作方式不能很好地结合在一起,如果没有以一种或另一种方式做你自己的工作,或者找到(/制作)一些可以做到的库。如果您尚未加载这些图像,则 Masonry 将无法正常工作(您的卡片会显得折叠或重叠,因为当 Masonry 运行时,图像的大小为 (0px,0px)。它不会神奇地跟踪所有卡片的所有大小变化;您必须这样做,并告诉它何时加载更多项目或再次渲染。
      • @D.B 因此,您必须在绘制角度后调用 Masonry(以防它添加更多项目),并且在加载所有/每个图像之后。如果您错过任何步骤,您将遇到砌体错误。这并不复杂。这很复杂。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-16
      • 1970-01-01
      • 2016-12-05
      • 1970-01-01
      相关资源
      最近更新 更多