Backbone Marionette:在加载所有图像之前不要显示视图

时间:2014-10-27 13:48:42

标签: backbone.js marionette

我正在显示一个CompositeView,其中每个模型都有一个属性,它是图像的URL。如果我只是。在一个区域中显示图像尚未完成加载,这看起来不太性感(它们在加载时会显示)。

在显示视图之前,我想等到所有图像都已加载。现在,我试图通过延迟图像加载来使其工作,但这可能不是正确的方法(也许这应该在模型上完成?)。

applications/list_view.js

App.module("ApplicationsApp.List", function(List, App, Backbone, Marionette, $, _){

  List.Application = Marionette.ItemView.extend({
    tagName: 'li',
    template: Templates.applications.application
  });

  List.Applications = Marionette.CompositeView.extend({
    className: "applications",
    template: Templates.applications.applications,
    childView: List.Application,
    childViewContainer: "ul"
  });

});

applications/list_controller.js

App.module("ApplicationsApp.List", function(List, App, Backbone, Marionette, $, _) {

  List.Controller = {

    listApplications: function() {
      // Set layout
      App.trigger("set:layout:authenticated");

      // Fetch the applications
      var fetchingApplications = App.request('application:entities');

      $.when(fetchingApplications).done(function(applications) {

        var applicationsListView = new List.Applications({
          collection: applications
        });


        var deferreds = [];

        applications.each(function(application) {

          deferreds.push(function() {
            var loader = new Image();
            loader.onload = function() {
              console.log(application.get("image_path"));
            };
            loader.src = application.get("image_path");
          });

        });

        $.when.apply($, deferreds).then(function() {
          App.layout.mainRegion.show(applicationsListView);
        });

      });

    }

  };

});

2 个答案:

答案 0 :(得分:1)

我认为你的方法是正确的,我会尝试将数据/图像加载封装在一个函数中,可能使用存储库

    $.when(applicationsRepository.getAll()).then(function (apps) {
        var appsView = new App.Views.ApplicationListView({ collection: apps});
        App.layout.mainRegion.show(appsView );
    });

所以,这个代码将成为你控制器的一部分,就像你已经拥有它一样,当存储库完成加载时,控制器只是在视图上呈现数据,类似于带有存储库的服务器端MVC,

getAll()将包含您现在在控制器上加载数据和图像的代码,存储库将是您木偶应用程序的额外模块。

所以你的方法getAll就像

    var getAll = function () {
        var deferred = $.Deferred();
        _getAll(function (apps) {
            deferred.resolve(apps);
        });
        return deferred.promise();
    };

    var _getAll = function (callback) {
        //code to create the app collection
        apps.on("reset", function(apps){
            //load images
            //callback(apps);
        });
        apps.fetch({ reset: true });
    };

要在最后一个图像加载后识别并执行某些操作(回调),我可能会使用一个计数器设置总图像数(来自集合),并在每次执行加载处理程序时递减它。 $(window).load()可以是,并且在加载整个页面后将触发选项。

感谢。

答案 1 :(得分:0)

我最终这样做(灵感来自Wait for image to be loaded before going on):

applications/list_controller.js

App.module("ApplicationsApp.List", function(List, App, Backbone, Marionette, $, _) {

  List.Controller = {

    listApplications: function() {
      self = this;
      // Set layout
      App.trigger("set:layout:authenticated");

      // Fetch the applications
      var fetchingApplications = App.request('application:entities');

      // Perform actions when applications have been fetched
      $.when(fetchingApplications).done(function(applications) {

        // Load all images in applications
        var imgLoaders = [];

        applications.each(function(application) {
          var src = application.get("image_path");
          imgLoaders.push(self.loadImage(src));
        });

        // Perform actions when images have been loaded
        $.when.apply($, imgLoaders).done(function() {
          var applicationsListView = new List.Applications({
            collection: applications
          });
          App.layout.mainRegion.show(applicationsListView);
        });

      });

    },

    loadImage: function(src) {
      var deferred = $.Deferred();
      var img = new Image();
      img.onload = function() {
        deferred.resolve();
      };
      img.src = src;
      return deferred.promise();
    }

  };

});