Backbone JS + Handlebars JS - 如何避免多次呈现HTML

时间:2014-01-31 01:32:43

标签: backbone.js handlebars.js

我有一个Backbone应用程序,我通过事件单击触发View,并使用HandlebarsJS呈现Views HTML并显示集合中的数据。到目前为止它的工作原理除了我的HTML重复每个条目

我的HTML看起来像这样:

<header>
   <span class="blackdot" aria-hidden="true" />
   <h1>Overview</h1>
</header>
<div>
   <ul>
      <li>
        <a href="#">{{brand}}</a>
        <p>{{country}}</p>
    </li> 
  </ul>
</div>

现在,它复制了整个HTML代码块,包括<header><h1> - 每个条目的标记,但我想要实现的是我的HTML看起来像这样:

<header>
   <span class="blackdot" aria-hidden="true" />
   <h1>Overview</h1>
</header>
<div>
   <ul>
      <li>
        <a href="#">Audi</a>
        <p>Germany</p>
     </li>
      <li>
        <a href="#">Hyundai</a>
        <p>South Korea</p>
     </li>
      <li>
        <a href="#">Fiat</a>
        <p>Italy</p>
     </li>  
  </ul>
</div>

我的骨干视图看起来像这样:

 define(['backbone','handlebars', 'text!templates/Cars.html'],

    function(Backbone,Handlebars, Template) {

        'use strict';

        var CarsView = Backbone.View.extend({

            template: Handlebars.compile(Template),

            events: {
            },

            initialize: function () {
            _.bindAll(this, 'render');
            },

            render: function() {
               var self = this;
               self.collection.each(function(model){
                    self.$el.append(self.template({
                        brand:model.get('brand'),
                        country:model.get('country')
                        })
                    );
               });

                return this;
            }

        });

        return CarsView;

    }
 );

当然我可以在索引页面上定义大部分HTML,将它包装在DIV中并显示:none并且只在Handlebars HTML模板中写入<li> - 标签,但我想避免那个,因为返回的数据是字符串,我不能做{{#each}} - 事情......所以,有什么解决办法吗?

1 个答案:

答案 0 :(得分:1)

要添加到guzmonne所说的内容,您看到这个的原因是因为您正在循环整个模板。您应该做的是获取<li>并专门为他们制作新模板。我已经修改了你现有的代码,以显示你想要做的事情是如何实现的。

CarsView Handlebars模板:

<header>
    <span class="blackdot" aria-hidden="true" />
<h1>Overview</h1>
</header>
<div>
    <ul id="cars_list" />
</div>

CarsView Backbone View:

var CarsView = Backbone.View.extend({

    template: Handlebars.compile(Template),

    events: {},

    initialize: function () {
        _.bindAll(this, 'render');
    },

    render: function() {
        this.$el.html(this.template()); // this now only renders once
        this.addAll();
        return this;
    },

    addOne: function(car) {
        var view = new CarView({model: car});
        this.$("#cars_list").append(view.render().el);
    },

    addAll: function() {
        this.collection.each(this.addOne, this);
    }
});

我所做的与您原来的CarsView之间的主要区别在于,首先,模板本身不包含任何<li>。相反,我有一个占位符ID,标题为“cars_list”。这个容器将为我们提供一个入口点来循环遍历汽车收藏并添加每个项目。其次,我们没有循环遍历集合并重新渲染CarsView。相反,我们将CarsView放入DOM中并从那里手动应用到它。

通常在处理集合时,您可以利用Backbone的this.listenTo()函数,该函数可以执行诸如“重置”或“添加”之类的事件并将其绑定到函数。由于看起来集合已经被提取,我们只需在渲染CarsView模板后执行this.addAll()。正是在这里,集合被循环并添加。

要完成此任务,您需要另一个Backbone视图和另一个模板......

CarView Handlebars模板:

<a href="#">{{brand}}</a>
<p>{{country}}</p>

CarView骨干视图:

var CarView = Backbone.View.extend({
    tagName:  "li",

    template: Handlebars.compile(Template),

    events: {},

    initialize: function () {
        // model event listeners (in case these list items can be edited/removed)
        this.listenTo(this.model, 'change', this.render);
        this.listenTo(this.model, 'destroy', this.remove);
    },

    render: function() {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    }
});

CarView视图简短而简单,但为您提供了很多帮助。如您所见,此视图将生成<li>标记并获取模型的内容并将其发送到手柄模板。不再需要处理手动获取模型属性,这是一个额外的好处。