backbone.js
在上一教程中 ,我们深入研究了Backbone.js(用于构建应用程序的MV * JavaScript框架)的工作原理。 构建一个小型的冲浪商店应用程序(以帮助我们跟踪库存的冲浪板),我们研究了如何创建模型,将模型实例分组到集合中以及遍历集合以创建视图。 我们还通过将每个模型实例渲染到其自己的视图中并将它们分组到一个父视图中而进一步走了一步。 这是我们离开的地方 。
在本教程中,我们将了解最后一步的重要性,并将一些控制器类型的逻辑引入图中。 在上一篇文章中,我谈到了控制器类型的逻辑及其所属的位置,但是在继续之前,让我们先介绍一下这一点。
关注点分离
在MV *框架中,视图通常负责以下内容:
- 呈现UI,并向最终用户显示从数据库和/或集合中检索到的数据。
- 通过事件处理用户输入,并以某种方式将这些事件传达给模型。
“以某种方式”部分是控制器逻辑的来源。在Backbone.js中,我们能够在实例化过程中将事件绑定到视图。 如果我们想添加或删除库存,或完全删除模型,我们可以这样做。 我们将逐步介绍如何执行此操作,但是现在,想象一下在视图中有一个按钮可以让我们从库存中删除一件商品。 我们可以在视图中注册该事件,它实质上是控制器逻辑。 单击该按钮后,我们将与相应的模型进行通信,并对其进行必要的更新。 模型的更改也会触发视图可以处理的事件,最终重新渲染视图并显示正确的数据。
简而言之:
- 视图呈现模型数据并注册事件。
- 当通过用户输入触发事件时,我们可以运行某种与模型进行通信的回调或函数。
- 在模型内部,执行逻辑。 在现实世界中,您可能还会在此处更新数据库。
- 模型更改会触发事件。
- 视图在该事件上发生,并采取相应的行动,可能会重新呈现自己。
考虑到所有这些,我们现在首先需要考虑如何注册这些事件。 让我们继续。
使用骨干事件
根据骨干事件文档 :
事件是可以混入任何对象的模块,使对象能够绑定和触发自定义命名事件。
在Backbone应用程序中有许多处理事件的方法,但是我们将利用两种方法:
- 我们将结合使用内置事件的目录和
listenTo
方法, 该方法告诉对象侦听另一个对象上的特定事件。 - 我们还将使用事件哈希直接在视图内部委派事件 。
首先让我们看一下如何利用视图实例内部的事件散列。
利用事件哈希
这是上一次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;
}
});
您会注意到,每个视图实例都包装在自己的tr
元素中,该元素从我们之前制作的模板中填充。 让我们对该模板进行一些编辑,以包含几个按钮,使我们可以添加和删除库存。 我们还需要更新表的标记:
<table class="table">
<thead>
<tr>
<th>Manufacturer</th>
<th>Model</th>
<th>Stock</th>
<th>Add/Remove</th>
</tr>
</thead>
<tbody id="table-body"></tbody>
</table>
<script type="text/template" id="surfboard-template">
<td><%= manufacturer %></td>
<td><%= model %></td>
<td><%= stock %></td>
<td>
<button class="add-one">+1</button>
<button class="minus-one">-1</button>
</td>
</script>
现在,我们的每个视图实例都应该有两个按钮,但是目前它们什么也不做。 现在让我们看一下事件哈希,看看如何在这两个按钮上注册点击。 Backbone中的事件哈希通常如下所示:
events: {
'event target': 'callback'
}
该event
是实际的事件,如click
, dblclick
, mouseover
等。 target
是目标元件,其经由基于视图的元件上DOM遍历找到。 换句话说,如果我们指定了一个类名,一个ID或一个标记,它将查找与查找匹配的那个类型的第一个。 这就是为什么我将类名称添加到模板中的按钮的原因。 最后, callback
是触发事件时callback
的函数。
因此,在本例中,我们可以将以下内容添加到SurfboardView
视图中:
events: {
'click .add-one': 'addOne',
'click .minus-one': 'minusOne'
},
addOne: function(e) {
e.preventDefault();
// code to add one to stock here...
},
minusOne: function(e) {
e.preventDefault();
// code to minus one from stock here...
}
现在唯一缺少的是实际更新模型的脚本。
更新模型
如果将警报或控制台语句放在视图的addOne
或minusOne
函数中,然后通过单击按钮来触发事件,那么您将很快看到正在执行的事件。 但这并没有真正帮助我们,因为我们必须将此用户操作传达回模型。 到目前为止,我只是阻止了默认的浏览器按钮行为。 接下来,我们需要调用一个模型函数(仍然需要编写)。 这两个模型函数将驻留在模型本身内部,忠实于我们的“关注分离”思想。 这是更新的SurfboardView
:
var SurfboardView = Backbone.View.extend({
tagName: 'tr',
events: {
'click .add-one': 'addOne',
'click .minus-one': 'minusOne'
},
template: _.template($('#surfboard-template').html()),
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
},
addOne: function(e) {
e.preventDefault();
this.model.addOne();
},
minusOne: function(e) {
e.preventDefault();
this.model.minusOne();
}
});
请记住,每个视图实例都包含对其相应模型实例的引用。 这就是为什么我们能够使用this.model.FUNCTION
访问模型函数的this.model.FUNCTION
。 回到我们的Surfboard
模型中,我们需要考虑这些功能。
这里的逻辑很简单,因为我们只需要获取现有的存货编号,就可以对其进行加或减,然后更新该模型的存货编号。 我们已经研究了如何从模型中get
属性值。 同样,我们可以set
它。 这是更新的模型代码:
var Surfboard = Backbone.Model.extend({
defaults: {
manufacturer: '',
model: '',
stock: 0
},
addOne: function() {
this.set({
stock: this.get('stock') + 1
});
// probably update a database
},
minusOne: function() {
this.set({
stock: this.get('stock') - 1
});
// probably update a database
}
});
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
在现实世界中的应用程序中,您可能也想在此处更新数据库,但这超出了本教程的范围。
现在,如果运行此命令,您会注意到单击按钮时会触发事件,并且将更新模型实例中的相应属性值。 屏幕上什么也没有发生。 这是为什么? 好吧,我们还没有重新渲染关联的视图,所以让我们看一下。
在视图实例化上监听事件
这是一个快速的场景。 想象一下,我们已经将一个视图渲染到了屏幕上。 然后,用户与该视图进行交互,从而触发了模型的更改。 然后,该模型触发change
事件(我们知道可以从事件目录中触发该事件)。 更改该模型后,我们要重新渲染视图。 我们该怎么做?
首先,请记住,我们的视图实例中有一个初始化函数。 我们可以使用它来添加侦听器,如下所示:
initialize: function() {
this.listenTo(this.model, "change", this.render);
}
现在,我们的视图对象正在侦听模型对象上的更改,当确实发生更改时,我们将再次调用render函数,以更新视图。
你猜怎么了? 由于到目前为止我们已经编写了代码,因此我们已经在那儿了。 通过单击每个视图实例中的那些按钮,我们不仅在运行关联回调函数,而且还触发了change事件。 这意味着,通过在我们的视图中插入这一小段代码,当模型的change事件触发时,我们能够做任何我们想做的事情。 看一下我们更新的SurfboardView
代码:
var SurfboardView = Backbone.View.extend({
tagName: 'tr',
events: {
'click .add-one': 'addOne',
'click .minus-one': 'minusOne'
},
template: _.template($('#surfboard-template').html()),
initialize: function() {
this.listenTo(this.model, "change", this.render);
},
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
},
addOne: function(e) {
e.preventDefault();
this.model.addOne();
},
minusOne: function(e) {
e.preventDefault();
this.model.minusOne();
}
});
现在,一切都应该正常工作,并且您应该能够像这样添加和减去库存! 这是与之配套的演示和代码库:
请参阅CodePen上的SitePoint ( @SitePoint )的Pen Backbone.js基础知识-第4部分 。
结语
伙计们,那真是太好了! 在本教程中,我们在使用Backbone方面取得了很大的进步,并研究了事件的重要性以及如何使用它们。 我们还探讨了视图和模型之间的通信线路如何工作,以及如何使代码井井有条,以使其更具面向未来性和可扩展性。 Backbone不仅拥有更多功能,而且文档中充满了有趣的事件,方法和可能性。 如果您有任何问题或意见,我们很高兴在下面的讨论中听到他们的意见。 继续探索和建设,并感谢您的阅读。
想要更多有关Backbone的信息吗?
SitePoint Premium在Backbone.js上有新课程。 加入Premium来访问它,以及整个SitePoint资源库!
backbone.js