0

バックボーンを使用して画像ギャラリーを構築しています。ユーザーは一度に 1 つの画像しか表示できません。矢印キーを使用して次/前に移動すると、コレクション内の次の画像が表示されます。

ギャラリー ビューと呼ばれるトップ レベルのバックボーン ビューが 1 つあります。

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

次に、画像ごとにビューを作成します

PhotoView = Backbone.View.extend

ビューにあるコレクション内の現在のモデルを追跡し、そのモデルの photoView を作成します。

私の質問は、ページネーション、または表示されていない画像のプリフェッチに関するものです。galleryView が複数の PhotoViews を保持し、フォーカスされているものを表示する方法についてはわかりません。コレクション全体に対して 1 つの長い div を作成し、各写真の div をインデックス付きの位置に追加することを考えています。そのdivから新しい画像を削除して追加する戦略は何でしょうか。

4

2 に答える 2

1

アップデート

元のコードを変更しました。これは明らかにテストされていませんが、妥当なスタートが切れるはずです。img要素が作成され、src属性が設定されるとすぐに、画像のプリロードが開始されます (ここで説明したように)。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 が複数の PhotoViews を保持し、フォーカスされているものを表示する方法についてはわかりません。

これは簡単な部分です。ビューが DOM にアタッチされていない限り、ビューは非表示のままです。必要な数のビューをインスタンス化して、いつでもそのうちの 1 つだけをアタッチすることができます。

コレクション全体に対して 1 つの長い div を作成し、各写真の div をインデックス付きの位置に追加することを考えています。そのdivから新しい画像を削除して追加する戦略は何でしょうか。

とにかく、画像ごとにLIを使用してULを作成します。画像を事前にロードしたい場合は、次の行で十分だと思います。写真の数が不条理でない限り、PhotoViewを削除する必要はありません。ビューをスクロールして非表示にするか、ビューを実際に削除したい場合は remove() を呼び出します。

于 2013-04-11T23:24:01.587 に答える