如何使下划线模板相互交互?

时间:2016-08-10 14:10:11

标签: javascript templates backbone.js underscore.js

我的Backbone.js项目中有两种类型的模板。 单项模板和项目清单模板。

此外,项目中有两种类型的视图: 单项模板和项目列表。

我使用RequireJS来使应用程序模块化。所以,我想,保持模板分离是一个很好的做法。但是有一个问题:我不能让我的模板“沟通”。当我渲染CollectionView时,它只在页面中生成一个元素 - 空<ul id="spaceman-list">并且其中没有项目集合。在我的listview中,我使用addItem functuion按itemView包装每个集合项,但它不起作用。该列表不会在dom中呈现。

我不想使用像_.each()这样凌乱的东西,我想保持我的代码干净。

这是两个视图代码:列表视图

// app/js/views/spaceman-list.js

'use strict';

(function(w) {

    define([
        'jquery',
        'underscore',
        'backbone',
        '../models/spaceman',
        '../views/spaceman-item',
        '../collections/spaceman-collection',
        'text!../templates/spaceman-list.html'
    ], function($, _, Backbone, SpacemanModel, SpacemanItemView, SpacemanCollection, listTemplate) {
            var SpacemanListView = Backbone.View.extend({
                el: '#container',
                render: function() {
                    this.collection.on('reset', this.addItem, this);
                    this.collection.each(this.addItem, this);
                    var data = {
                        spacemen: this.collection.models
                    };
                    var compiled = _.template(listTemplate, data);
                    this.$el.html(compiled);
                    return this;
                },
                addItem: function(item) {
                    var newSpaceman = new SpacemanItemView({model: item});
                    this.$el.find('ul').append(newSpaceman.render());
                }
            });
            return SpacemanListView;
    });

   })(window);

项目视图:

  // app/js/views/spaceman-item.js
 'use strict';

 (function(w) {

    define([
        'jquery',
        'underscore',
        'backbone',
        '../models/spaceman',
        'text!../templates/spaceman-item.html'
    ], function($, _, Backbone, SpacemanItem, itemTemplate) {
            var SpacemanItemView = Backbone.View.extend({
                el: '#spaceman-list',
                render: function() {
                    var data = {
                        spaceman: this.model
                    };
                    this.$el.html(_.template(itemTemplate, data));
                },
            });
            return SpacemanItemView;
    });

 })(window);

而且,正如我上面所说,我将下划线模板分开: 这是列表模板:

// app/js/templates/spaceman-list.html
<ul id="spaceman-list"></ul>

这是项目模板:

// app/js/templates/spaceman-item.html
<li><% spaceman.get('name') %></li>

而且,我在这里添加了我的app入口点:

// app/js/application.js
'use strict';

(function(w) {
   define([
   'jquery',
   'underscore',
   'backbone',
   'collections/spaceman-collection',
   'views/spaceman-list'
   // Request router.js
   ], function($, _, Backbone, ItemsList, ListView) {
        var App = Backbone.View.extend({
                initialize: function(){
                // Pass in our Router module and call it's initialize function
                console.log('Yeeha!');
                var endurance = new ItemsList([
                                {name: 'Cooper'},
                                {name: 'Brend'},
                                {name: 'Romilly'},
                                {name: 'Doyle'},
                                {name: 'Mann'}
                            ]);

                console.log(endurance);

                    var view = new ListView({collection:endurance});

                    view.render();
                }
          });

            return App;
   });

})(window);

我只是为此疯狂。如何制作单独的模板以“看到”彼此?

1 个答案:

答案 0 :(得分:1)

你在SpacemanListView#addItem中说出这个:

this.$el.find('ul').append(newSpaceman.render())

SpacemanItemView#render不会返回任何内容:

render: function() {
    var data = {
        spaceman: this.model
    };
    this.$el.html(_.template(itemTemplate, data));
},

SpacemanItemView也说:

el: '#spaceman-list'

所以当SpacemanItemView函数说el时,所有render个实例都会尝试使用相同的this.$el.html(...)。大概是您的templates/spaceman-list.html包含<ul id="spaceman-list">或类似内容,因此#spaceman-list在收集视图放置在页面上之前不会解析为任何内容;但是你在集合视图出现在页面之前调用addItem,所以项目视图都试图渲染到同一个不存在的元素中。

解决方案有两个方面:

  1. render函数传统上return this;,以便调用者可以$container.append(view.render().el)将内容放在页面上,这样做。
  2. 在视图定义中使用预定义的el(即el: '#something')会导致各种排序和事件问题,当每个视图创建并拥有自己的el时,事情会更好。< / LI>

    addItem看起来应该更像这样:

    addItem: function(item) {
        var newSpaceman = new SpacemanItemView({model: item});
        this.$('ul').append(newSpaceman.render().el);
    }
    

    注意this.$快捷方式和.el来电中的append

    然后我们重新审视项目视图:

    var SpacemanItemView = Backbone.View.extend({
        tagName: 'li',
        render: function() {
            var tmpl = _.template(itemTemplate);
            this.$el.html(tmpl({ spaceman: this.model }));
            return this;
        },
    });
    

    不再el但现在我们有tagName: 'li',这会告诉Backbone创建一个空的<li>作为视图的elel documentation涵盖了各种视图属性如何用于确定el的内容。

    另请注意_.template(tmpl, data) _.template形式的templates/spaceman-item.html stopped working in Underscore 1.7.0,所以我也解决了这个问题。

    您还需要调整<li>模板,使其只是<% spaceman.get('name') %> 的内容:

    el

    我建议对集合视图进行类似的更改,以便它也创建并拥有其pip uninstall setuptools download https://bitbucket.org/pypa/setuptools/raw/0.7.3/ez_setup.py