javascript - 如何在 marrionete.js 中构建调用链渲染 itemView,并使用 itemView 内的异步函数进行延迟

标签 javascript jquery callback marionette deferred

我的结构非常简单

ProductsList.TileListView = Marionette.CollectionView.extend({
    tagName: 'section',
    className: 'b-list-viewtile',
    template: '/static/js/app/list/modules/productslist/templates/tileList',
    childView: ProductsList.TileItemView

});



ProductsList.TileItemView = Marionette.ItemView.extend({
    tagName: "article",
    className: "b-list-viewtile__item",
    template:  '/static/js/app/list/modules/productslist/templates/tileItem',
    _getImage: function(){

        var _this = this;

        var img =  new Image();
        img.src = this.model.get("media");
        img.onload = function(){
            msnry.append( _this.$el )
                .masonry( 'appended', _this.$el ).masonry('layout');
        };
    }
}); 

但我使用 Masonry 插件来对齐网格上的项目。

问题是,对于每个项目,我需要知道变量的值,例如图像的高度。

这意味着构建每个 itemView 我只能将前一个项目附加到 DOM 中。

维护集合中的顺序也很重要 - 集合中的第一个应该首先渲染,等等。

花了很多时间研究文档但没有找到优雅的解决方案

有人能告诉我如何构建那个“链”吗?每个项目都必须等待先前渲染,但最终结果顺序必须保持在集合中,而不是图像加载优先级中。

我认为这是关于 defered+marrionette.callback 并覆盖 native AttachHtml 或 buildChildView

非常感谢:)

最佳答案

我们将使用 Marionette 内置的 Marionette.Babysitter 和 ES6 Promises 来解决您的问题。

如果您阅读 docs仔细(或浏览源代码)您将了解到 Marionette 按集合顺序呈现 subview 。

By default the CollectionView will maintain the order of its collection in the DOM.

此外,所有 CollectionView 还将按照其渲染顺序保存对其所有 subview 的引用,这也是按照其集合排序顺序。

您想要的是确保所有 subview 都已渲染,然后添加该 subview el到您的砌体项目列表,按顺序

首先,设置您的 Promise

我们将修改您的 subview 的 ._getImage稍微修改一下方法,并让它返回一个 Promise:

_getImage: function(){
    var _this = this;
    return new Promise(function (resolve, reject) {
      var img =  new Image();
      img.src = this.model.get("media");
      img.onload = function(){
          resolve();
      };
    });
}

当加载此任意 subview 的图像时, getImage 返回的 promise 将得到解决。这对我们有什么帮助?继续阅读。

其次,等待所有图像加载完毕

在您的 CollectionView 中,您将添加此属性 onRenderCollection ,当所有 subview 完成渲染时,Marionette 会触发该事件。在这里,使用 Babysitter,我们将解雇 _getImage方法,并设置您正在寻找的 Masonry promise 链。

onRenderCollection: function () {
  var promises = [];
  this.children.each(function (childview) {
    promises.push(childview._getImage()); // return the promise
  })
  // When all your children view's images have loaded we begin to fill Masonry
  Promise.all(promises).then(_.bind(function () {
    this.children.each(function (childview) {
      childview.addToMasonry();
    }
  }, this))
}

第三,添加到 Masonry!

当然,我们还没有名为 addToMasonry 的属性你 child 的观点,但我假设你会使用一个看起来很像你的img.onload上的东西打回来。像这样的事情

addToMasonry: function () {
  masonry.append( this.$el )
    .masonry( 'appended', this.$el ).masonry('layout');
}

缺点

使用此方法的一个警告是,您首先必须等到所有 subview 都渲染完毕。如果列表很长(超过 1000 个),这可能是一个性能问题,并且解决方法可能并不简单。

关于javascript - 如何在 marrionete.js 中构建调用链渲染 itemView,并使用 itemView 内的异步函数进行延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30330178/

相关文章:

javascript - JSON 字符串中的数学方程式

javascript - Kendo UI - 来自 JSON 数组的柱形图

angular - HTML中未发现 Angular 值变化

Javascript 函数回调依赖于超时

javascript - CouchDB 在时间戳内获取结果

javascript - SoundCloud Api 重定向混淆和 Audio Api Streams

javascript - 在 javascript Jquery 中,如何确定从顶部到当前状态的位置...每次有人滚动?

jquery - datepicker - beforeShowDay 不起作用

javascript - 在 anchor 标记之前附加到 ul

java - 异步任务技术