BackboneJs Collections 和 Rest API 调用

BackboneJs Collections and Rest API calls

我目前正在 backbone 中写博客 - 在此之前,我创建的任何 backbone 应用程序都相当小,所以我应该在初始化时获取我所有的 collection在应用程序上,将其存储在 collections 中并将它们传递给 collections 以供使用。

我面临着处理大量数据(博客文章)的问题。我不认为在一次调用中加载所有数据是最好的主意。我想做的是创建分页,它最初会请求说 9 条记录,计数为 post 和计数的当前页,然后对于每一页,我们对下一组数据等发出新请求。

请记住,我也在构建 Rest API,因此我对响应的格式没有任何限制。

我非常想按照 backbone 中的 collection 概念进行此操作 - 这可能吗?

如果有人以前做过这个或者有任何想法可以帮助我,那么将不胜感激。

你可以这样做:

var BlogPostsCollection = Backbone.Collection.extend({

    url: function() {
        return 'posts?page='+this.page;
    },

    fetch: function(options) {
        this.page = options && options.page || 0;

        return Backbone.Collection.prototype.fetch.apply(this, arguments);
    },

    parse: function(resp, options) {
        var models = resp;

        return _.map(models, function(model) {
            model.page = options.page;
            return model;
        });
    }

});

var BlogPostsView = Backbone.View.extend({

    syncedPages: [],

    events: {
        'click .page': 'onPageClick'
    },

    initialize: function() {
        this.filteredCollection = new Backbone.Collection();

        this.listenTo(this.collection, 'request', this.onCollectionRequest);
        this.listenTo(this.collection, 'sync', this.onCollectionSync);
        this.listenTo(this.filteredCollection, 'reset', this.onFilteredCollectionReset);

        this.requestingPage = 0;
        this.collection.fetch({
            page: this.requestingPage
        });

        this.render();
    },

    onPageClick: function(e) {
        e.preventDefault();

        this.requestingPage = +e.target.dataset.page;

        if (this.syncedPages.indexOf(this.requestingPage) < 0) {
            this.collection.fetch({
                page: this.requestingPage,
                remove: false // Important - merge the response models
            });
        } else {
            this.filterToPage(this.requestingPage);
        }
    },

    onCollectionRequest: function() {
        this.filteredCollection.reset();
        this.render();
    },

    onCollectionSync: function(collection, response, options) {
        if (options.page === this.requestingPage) {
            this.filterToPage(this.requestingPage);
        }

        this.syncedPages.push(options.page);
    },

    onFilteredCollectionReset: function() {
        this.render();
    },

    filterToPage: function(page) {
        this.currentPage = page;
        this.filteredCollection.reset(this.collection.where({ page: page }));
    },

    render: function() {
        if (!this.filteredCollection.length) {
            this.$el.html('<p>Loading...</p>')
        } else {
            this.$el.empty();
            this.filteredCollection.each(function(postModel) {
                this.$el.append('<p>'+postModel.get('title')+'</p>');
            }, this);
        }

        this.$el.append('<a href="#page0" class="page" data-page="0">Page 0</a> | <a href="#page1" class="page" data-page="1">Page 1</a>');
    }

});

var blogPostView = new BlogPostsView({
    el: $('#app'),
    collection: new BlogPostsCollection()
});

显然该视图用于演示目的 - 使用 html 字符串,一个接一个地附加博客文章是次优的,应该有一个 BlogPostView 和一个 BlogNavigationView 等。

注意我添加了一些奖励逻辑:

  • 页面抓取后,不需要重新抓取(remove:false + syncedPages)
  • 如果出现多个请求,则不会混淆要显示的请求(由于 requestingPage 变量)。如果您点击第 1 页,然后返回第 0 页,它会立即再次显示第 0 页,但它会在后台缓存第 1 页。

演示:http://jsfiddle.net/ferahl/sfyqt7wr/