Backbone.js基础:模型,视图,集合和模板

在本教程中,我们将探讨流行的MV *框架Backbone.js的基础知识。 我们将研究模型,视图,集合和模板,并了解在构建应用程序时两者如何相互构建。 我们还将探讨责任和关注点分离,最终为我们构建具有合理代码库的可扩展应用程序铺平道路。

骨干网只有一个硬依赖性,那就是Underscore.js。 我们还将利用jQuery轻松进行DOM操作。 您的典型文档结构应如下所示:

<html>
<body>

app content here

<script src="path/to/jquery.js">
<script src="path/to/underscore.js">
<script src="path/to/backbone.js">
<script src="path/to/app.js">

</body>
</html>

所有应用程序脚本必须包含在各个库之后。 除此之外,我们已经准备好潜水!

Backbone.js和MV *模式

骨干落在MV *框架的伞,这意味着它主要由M odels和V IEWS的下。 传统的MVC框架包含额外的C ,代表控制器。 从历史上看,控制器会响应某种类型的用户输入,并将该输入传达给模型或返回到视图。 但是,在像Backbone这样的MV *框架中,控制器逻辑是在视图本身内部处理的。 要进一步了解JavaScript MV *框架的结构, 请查看这篇文章。

不过,由于我们没有研究什么模型和视图,因此我们在这里有些犹豫。 好吧,这并不复杂! 我试图将模型视为“数据模型”,就像建筑师可能具有房屋模型或工程师可能具有机翼模型一样。 考虑到这一点,更容易理解特定模型如何表示特定数据集。 在生产级应用程序中,该数据可能存储在某个地方的数据库中。 模型因此可以与该数据库通信,并执行某些操作,例如CRUD操作。

意见呢? 给定“视图”的名称,就很容易得出关于他们的责任的假设。 如果您认为这是为最终用户呈现数据,那么您基本上是正确的。 意见确实对此负责。 但是,在骨干网中,它们还具有我之前提到的另一项主要功能。 它们处理控制器逻辑。 在本系列的第二部分中,我将进入视图内部的事件处理,与模型进行通信,然后将更新发送回视图。 现在,重要的是要了解该逻辑确实存在,但是存在于视图内部。 让我们进入模型,并更好地理解它们。

挖掘模型

这是有关模型Backbone文档的一些摘录:

模型是任何JavaScript应用程序的核心,它包含交互式数据以及围绕它的大部分逻辑:转换,验证,计算的属性和访问控制。

考虑到这一点,让我们起草一个小示例,以供日后使用。 想象一下,我们正在经营一家冲浪店,并且我们想建立一个我们携带的冲浪板数据库。 这样,如果客户问我们是否有特定制造商提供的电路板,或电路板的确切型号,或两者都有,我们可以进行快速查找。 我们还假设我们要跟踪库存。 我们的模型层次结构如下所示:

Surfboard
  |__manufacturer
  |__model
  |__stock

在Backbone中,我们通过扩展Backbone.Model创建一个新模型,如下所示:

var Surfboard = Backbone.Model.extend({

});

现在,我们可以使用如下构造函数创建该模型的新实例:

var board1 = new Surfboard({
  manufacturer: 'Channel Islands',
  model: 'Whip',
  stock: 12
});

现在,变量board1引用了Surfboard模型的新实例,并包含其自己的一组值。 就目前而言,我们可以传递任何值。 让我们使用defaults函数向模型添加一些默认属性。 现在,它应如下所示:

var Surfboard = Backbone.Model.extend({
  defaults: {
    manufacturer: '',
    model: '',
    stock: 0
  }
});

如果要从该实例中获取一些数据,可以使用get ,它从模型中获取属性的当前值。 假设我们在文档中有这个标记:

<table class="table">
  <tr>
    <th>Manufacturer</th>
    <th>Model</th>
    <th>Stock</th>
  </tr>
  <tr>
    <td id="board1-manufacturer"></td>
    <td id="board1-model"></td>
    <td id="board1-stock"></td>
  </tr>
</table>

我们可以像这样填充这些字段:

$('#board1-manufacturer').html(board1.get('manufacturer'));
$('#board1-model').html(board1.get('model'));
$('#board1-stock').html(board1.get('stock'));

结果如下,其中包括第二个模型实例:

请参阅CodePen上的SitePoint@SitePoint )的Pen Backbone.js基础知识-第1部分

到目前为止,这一切似乎有些漫长……毕竟,我们可以手动输出此数据。 但是,通过将模型分组到一个集合中,我们能够执行迭代过程来输出数据,注册事件,更改模型,重新呈现数据以及进行工作。

还要记住,在生产应用程序中,我们很可能通过从数据库中读取来生成模型实例。 这也增加了将模型分组到集合中的必要性。 事不宜迟,让我们来看一下。

创建收藏

假设在最初的应用程序加载期间,我们对冲浪板数据库运行了一个查询,并遍历了所有冲浪板。 在该循环过程中,我们获取了一些数据并创建了新的模型实例。 由于目前没有数据库,因此我将仅使用已经创建的两个模型实例,然后添加第三个。

现在,在我们的应用程序中,我们希望以表格形式输出所有数据。 以前,我们手动输出每个模型实例的属性,这是非常不切实际的。 不过,这次,我们创建一个Backbone集合 (一组有序的模型),并将模型添加到其中。 我们将从创建我们的集合(称为Surfboards

var SurfboardsCollection = Backbone.Collection.extend({

});

让我们将集合模型设置为我们的Surfboard模型,这使我们可以指定集合包含的模型类:

var SurfboardsCollection = Backbone.Collection.extend({
  model: Surfboard
});

现在我们的集合已建立,我们可以使用add方法将模型添加到集合中 。 让我们添加三个冲浪板,方法是首先创建集合的一个新实例,然后一次添加一个板实例:

var Surfboards = new SurfboardsCollection;
Surfboards.add(board1);
Surfboards.add(board2);
Surfboards.add(board3);

现在,我们所有的模型都已分组并准备好进行渲染。 在我们的HTML中,让我们删除之前的表行,并仅添加一个普通表主体。 现在我们的表应该如下所示:

<table class="table">
  <thead>
    <tr>
      <th>Manufacturer</th>
      <th>Model</th>
      <th>Stock</th>
    </tr>
  </thead>
  <tbody id="table-body"></tbody>
</table>

现在,我们可以使用一种可用的Underscore方法来遍历集合并输出数据。 我们将使用each ,可以将其直接应用到我们的集合中,并且还接受一个表示模型的参数。 因此,在每次迭代中,我们都可以访问当前模型,并且可以执行模型方法。 考虑到这一点,呈现结果表很简单:

Surfboards.each(function(surfboard) {
  $('#table-body').append(
    '<tr>' +
      '<td>' + surfboard.get('manufacturer') + '</td>' +
      '<td>' + surfboard.get('model') + '</td>' +
      '<td>' + surfboard.get('stock') + '</td>' +
    '</tr>'
  );
});

这是实际的演示:

请参阅CodePen上的SitePoint@SitePoint )的Pen Backbone.js基础知识-第2部分

到目前为止,它看起来很棒,并且在某些方面,我们已经手动渲染了一个视图。 但是,以这种方式进行操作非常有局限性,并且不允许我们利用Backbone的全部方法。 这也不允许我们即时执行任何控制器逻辑。 我们需要使用Backbone视图正确渲染数据,因此让我们继续进行下去。

使用视图和模板渲染数据

在建立我们的观点之前,让我们谈谈一个简洁的主题-模板。 模板使我们能够轻松呈现UI,作为直接DOM操作的替代方法。 尽管我们可以使用所需的任何东西,但是Underscore附带了自己的模板引擎 ,因此我们将利用它。

在我们的HTML中,让我们创建一个负责渲染模型数据的模板。 它看起来应该像这样:

<script type="text/template" id="surfboard-template">
  <td><%= manufacturer %></td>
  <td><%= model %></td>
  <td><%= stock %></td>
</script>

现在可以在视图中调用我们的模板,以轻松呈现数据。 注意,我还没有包含包装的tr元素,您很快就会知道为什么。

现在让我们继续创建视图。 根据文档:

通常的想法是将界面组织成由模型支持的逻辑视图,当模型更改时,每个视图都可以独立更新,而不必重新绘制页面。

现在考虑一下我们的应用程序,并考虑如何使它成为未来的证明。 在本教程中,我们仅渲染一次数据。 但是,如果将来我们希望能够更新模型实例属性该怎么办? 我们绝对希望引用每个模型实例,并将必要的控制器逻辑附加到该特定实例。 考虑到这一点,我们需要为我们的应用提供两个视图:

  1. 主(或父)视图,其中包含所有子视图。 我们将此称为SurfboardsView
  2. 子视图,负责呈现一个模型的单个实例。 我们称这些为SurfboardView

我们将首先通过扩展Backbone的View方法来创建SurfboardsView ,如下所示:

var SurfboardsView = Backbone.View.extend({

});

现在让我们包括以下三件事:

  1. elDOM元素 。 视图必须始终具有DOM元素。 在主视图中,我们将使用#table-body
  2. initialize函数,在创建视图的新实例时立即运行。
  3. render功能,可从模型数据中渲染视图模板。

这是我们的更新视图:

var SurfboardsView = Backbone.View.extend({

  el: '#table-body',

  initialize: function() {

  },

  render: function() {

  }

});

因为我们正在手动将模型实例插入到集合中,所以我们不必等待任何事件被触发来表示数据获取已完成。 这意味着我们可以立即在视图中调用render函数。 现在,我们的initialize函数如下所示:

initialize: function() {
  this.render();
}

在我们的render函数中,让我们开始做一些事情。 首先,我们将确保所讨论的元素没有HTML。 其次,让我们遍历我们的收藏。 第三,让我们返回this ,它启用链式调用。 这给了我们:

render: function() {
  this.$el.html('');

  Surfboards.each(function(model) {
    // do something...
  });

  return this;
}

到目前为止,一切都很好。 我们只需要完成render功能即可。 但是,我们到底需要在这里做什么? 步骤如下:

  1. 在每次循环迭代中,我们需要创建一个新的SurfboardView视图,并确保传入正确的数据(即当前模型)。
  2. 从创建的视图实例中,我们需要调用该视图的render函数,并返回填充的HTML元素。
  3. 在检索呈现的SurfboardView ,我们需要将其附加到我们设置的表主体元素中。

请记住,可以在任何点检索由el表示的视图元素。 有了这些知识, SurfboardsViewrender功能如下所示:

render: function() {
  this.$el.html('');

  Surfboards.each(function(model) {
    var surfboard = new SurfboardView({
      model: model
    });

    this.$el.append(surfboard.render().el);
  }.bind(this));

  return this;
}

在这里注意几件事。 首先是我们将当前模型传递给每个新的SurfboardView视图实例,以便可以从每个这些实例内部访问其属性。 其次,我们需要绑定thiseach环路由于时生成一个新的作用域上下文。

现在,如果您运行脚本,则实际上什么也不会发生。 那是因为我们还没有定义和设置SurfboardView 。 来做吧。 我们将再次通过扩展Backbone的视图开始:

var SurfboardView = Backbone.View.extend({

});

这次,我们要定义一个将使用模型属性填充的tagName 。 如果您还记得我们以前的模板,那么您还将记住我们从未包含包装的tr元素。 那是因为这是我们定义它的地方,最终创建了一个新元素。

我们还将要创建对视图模板的引用,该引用将在render function 。 最后,内部render功能,我们通过利用模板填充视图的元素和模型属性,并返回this为链接,像以前一样。 这是SurfboardView的最终脚本:

var SurfboardView = Backbone.View.extend({

  tagName: 'tr',

  template: _.template($('#surfboard-template').html()),

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

});

真好! 现在,我们在SurfboardsView创建的各种实例可以访问相应的render函数和元素。

最后但并非最不重要的一点是,我们需要通过实例化SurfboardsView来运行应用程序,如下所示:

var app = new SurfboardsView;

太棒了,您应该会看到桌子上摆满了我们的冲浪板型号! 以下是演示它的实际演示:

请参阅CodePen上的SitePoint@SitePoint )的Pen Backbone.js基础知识-第3部分

包起来

这将在Backbone.js探索的这一部分中完成。 今天,我们在这里讨论了很多基础知识,还讨论了一些用于可伸缩性和向前移动的出色技术。 下次,我们将研究实现一些控制器逻辑,并探索一些带有事件的视图到模型的通信,以及视图更新。 如果您有任何疑问或意见,我们很高兴在下面的讨论中听到他们的意见。 谢谢阅读!

在骨干上想要更多?

SitePoint Premium在Backbone.js上有新课程。 加入Premium来访问它,以及整个SitePoint资源库!

From: https://www.sitepoint.com/backbone-basics-models-views-collections-templates/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值