0

我正在使用主干构建一个图片库。用户一次只能查看一个图像,当他使用箭头键导航下一个/上一个时,他将看到集合中的下一个图像。

我有一个称为画廊视图的顶级主干视图。

GalleryView = Backbone.View.extend({
    initialize: function(options) {
        this.collection = PhotosCollection();
    }
});

然后为每个图像创建一个视图

PhotoView = Backbone.View.extend

我将跟踪视图中集合中的当前模型,并为该模型创建 photoView。

我的问题是关于分页或预取不在视图中的图像。我不确定galleryView 如何保存多个PhotoView,然后显示焦点所在的那个。我正在考虑为整个集合构建一个长 div,然后将每张照片的 div 添加到索引位置。从该 div 添加删除新图像的策略是什么。

4

2 回答 2

1

更新

我修改了我的原始代码。虽然这显然未经测试,但它应该给你一个合理的开始。一旦img创建了元素并src设置了属性(如here所述),图像就会开始预加载。它们不必附加到 DOM。我在下面包含的这个改进版本将根据paginationPadding变量在当前图像之前和之后预加载图像。

结束更新

在 Backbone 中处理事物时,它有助于将所有与状态相关的信息保留在模型中,然后让 UI 响应它。在这种情况下,您可以简单地跟踪要在模型中显示的图像,然后响应模型中的更改跟踪您要查看的照片,您可以简单地重新渲染照片库以显示所需的图片。它是反应性的。

这是一个粗略的实现,但希望能让您了解如何实现一个图库,您可以在其中单击像这样的照片。当然,你仍然有一堆 CSS 之类的事情要做。它不完整。如果您有任何问题,请告诉我。

var StateModel = Backbone.Model.extend({
  defaults: {
    visibleImage: 0
  },

  initialize: function(attributes, options) {
    this.photoCollection = options.photoCollection;
  },

  setIndex: function(photoIndex) {
    if(!this.photoCollection.length) return;

    if(photoIndex < 0) {
      photoIndex = this.photoCollection.length - 1;
    } else if(photoIndex >= this.photoCollection.length) {
      photoIndex = 0;
    }

    this.set('visibleImage', photoIndex);
  },

  setPrev: function() {
    this.setIndex(this.get('visibleImage') - 1);
  },

  setNext: function() {
    this.setIndex(this.get('visibleImage') + 1);
  }
});

var PhotoControls = Backbone.View.extend({
  tagName: 'div',

  initialize: function(options) {
    this.stateModel = options.stateModel;
    this.paginationPadding = options.paginationPadding;
  },

  render: function() {
    var that = this;
    this.$el.empty();

    var ctrlStyle = {cursor: 'pointer', display: 'inline-block', padding: '5px 10px', margin: '0px 5px', border: '1px solid #000'};

    this.$el.append($('<div><< Previous</div>')
      .css(ctrlStyle))
      .click(function() {
        that.stateModel.setNext();
      });

    // Display numbers
    var visibleImage = this.stateModel.get('visibleImage');
    var pgStart = Math.max(visibleImage - this.paginationPadding, 0);
    var pgEnd = Math.min(visibleImage + this.paginationPadding, this.stateModel.photoCollection.length - 1);
    for(var i = pgStart; i <= pgEnd; i++) {
      var $numEl = that.$el.append(
        $('<div>' + (i + 1) + '</div>')
          .css(ctrlStyle)
          .click(function() {
            that.stateModel.setIndex(i);
          });

        if(i == visibleImage) {
          $numEl.css({fontWeight: 'bold', textDecoration: 'underline'});
        }
      );
    }

    this.$el.$('<div>Next >></div>')
      .css(ctrlStyle))
      .click(function() {
        that.stateModel.setPrev();
      });

    return this;
  }
});

var PhotoView = Backbone.View.extend({
  render: function() {
    this.$el.html('<img src="' + this.model.get('url') + '" />');

    return this;
  }
});

var GalleryView = Backbone.View.extend({
  tagName: 'div',

  initialize: function(options) {
    this.paginationPadding = 2;

    this.collection = PhotosCollection();
    this.renderedViews = {};
    this.state = new StateModel(null, {photoCollection: this.collection});
    this.photoControls = new PhotoControls({
      stateModel: this.state,
      paginationPadding: this.paginationPadding
    }).render();
  },

  render: function() {
    if(this.photoView) {
      this.photoView.remove();
    }

    // Pre-fetch images before and after current one based on pagination padding
    var visibleImage = this.stateModel.get('visibleImage');
    var pgStart = Math.max(visibleImage - this.paginationPadding, 0);
    var pgEnd = Math.min(visibleImage + this.paginationPadding, this.stateModel.photoCollection.length - 1);

    for(var i = pgStart; i <= pgEnd; i++) {
      if(!this.renderedViews[fetchModel.cid]) {
        // Images will begin fetching as soon as the 'src' attribute is set on the 'img' element rendered by the view
        this.renderedViews[model.cid] = new PhotoView(this.collection.at(i));
        this.renderedViews[model.cid].render();
      }
      this.$el.html(this.photoView.render().el);
    }

    // Attach the view for the current image
    var renderModel = this.collection.at(this.state.get('visibleImage'));
    if(renderModel && this.renderedViews[renderModel.cid]) {
      this.photoView = this.renderedViews[renderModel.cid];
      this.$el.html(this.photoView.el);
    }

    this.$el.append(this.photoControls.el);

    return this;
  }
});
于 2013-04-12T00:43:49.597 回答
0

我不确定galleryView 如何保存多个PhotoView,然后显示焦点所在的那个。

这是简单的部分。只要视图没有附加到 DOM,它就保持不可见,您可以实例化任意数量的视图,并且在任何时候只附加其中一个。

我正在考虑为整个集合构建一个长 div,然后将每张照片的 div 添加到索引位置。从该 div 添加删除新图像的策略是什么。

为每张图片制作一个带有 LI 的 UL,无论如何,如果你想预加载图像,我想下一个就足够了,你不需要删除 PhotoViews,只要它们不是荒谬的照片数量,只是如果您希望实际删除视图,请调用 remove() 将它们滚动到视图之外或隐藏它们。

于 2013-04-11T23:24:01.587 回答