backbone.js
本文由Thomas Greco和Marc Towler进行同行评审。 感谢所有SitePoint的同行评审员使SitePoint内容达到最佳状态!
众所周知, Backbone.js是一个著名的MV *框架。 它托管在GitHub上,并通过提供具有键值绑定和自定义事件的模型,具有丰富的可枚举函数的API,具有声明性事件处理的视图的集合,并通过RESTful JSON将其全部连接到现有API,为Web应用程序提供结构接口。
在本文中,我们将使用称为事件的Backbone内置功能来实现异步消息传递范例,以避免耦合。 想法是将高度相互依赖的代码组分开。
我将展示的示例是一个图形可视化工具 ,其中数据可以很好地跨用户同步。 WebSockets的使用将有可能在用户的浏览器和服务器之间打开交互式通信会话。
目的是使示例尽可能简单。 此处学习的概念将有助于您减少耦合。 另外,这对于构建可扩展,灵活和可维护的代码是非常有用的方法。 在实验结束时,我们将得到以下结果:
Backbone.js
Backbone.js是一个通过提供模型 , 视图 , 控制器 , 集合和自定义事件来构建单页应用程序的框架。 它的结构帮助我们将用户界面与业务逻辑分开。 在本文中,我仅向您介绍其中一些元素,但是如果您需要更深入的指导,建议您阅读文章“ Backbone.js基础:模型,视图,集合和模板 ”。
模型代表数据,可以通过扩展Backbone.Model
来创建它:
var MyModel = Backbone.Model.extend({
initialize: function () {
console.log('model initialized');
}
})
视图是一种将用户界面组织为逻辑视图的方法,该逻辑视图由模型支持。 它不包含HTML标记,而只是包含向用户呈现模型数据的逻辑。 要创建视图,您需要扩展Backbone.View
,如下所示:
var MyView = Backbone.View.extend({
el: 'div#my-view-container',
initialize: function (options) {
this.model = new MyModel()
console.log('view initialized')
}
})
事件是可以混入任何对象的模块,使对象能够绑定和触发自定义命名事件。 模型和视图都具有此模块事件 ,这使我们能够将事件绑定到模型或视图 。 一种常见的模式是创建可监听模型更改的视图。 此技术通常旨在允许视图在基础数据更改时自动重新呈现自己。
为了给您示例这些元素如何协同工作的示例,我在CodePen上创建了一个演示 。
请参阅CodePen上的SitePoint( @SitePoint )提供的Pen XXpwMQ 。
每当我们更改输入时 , 视图都会更改我们的模型 。 按下“确定”按钮后,视图将呈现新的id
值。
服务器与客户端之间的实时通信
WebSockets是一种高级方式,可以打开用户浏览器和服务器之间的交互式通信会话。 使用此API,用户可以将消息发送到服务器并接收事件驱动的响应,而不必轮询服务器以获取答复。 该合同是描述规则和预期行为的协议,需要双方采取行动。 当这两个部分通过API链接在一起时,它充当了集成服务器和客户端的胶水 。
在桥梁类比中,一旦就位,数据和指令就可以越过桥梁。 例如,服务器接收一条指令,执行一个动作,然后在处理该指令后,它将信息返回给Web应用程序。 各方之间的互惠互利。 使用此抽象层(API) ,我们可以隐藏Web服务的复杂内容,而无需了解有关服务器如何执行操作的更多详细信息。
Socket.IO是一个用于实时Web应用程序JavaScript库。 它支持Web客户端和服务器之间的双向通信。 双方具有相同的API,并且像Node.js一样受事件驱动。 要打开浏览器和服务器之间的交互式通信会话,我们必须创建一个HTTP服务器以启用实时通信。 这将使我们能够发出和接收消息。 socket
是处理Web客户端与服务器之间的通信的对象。
下面的代码使用带有Express框架的 socket.IO创建该服务器。
var express = require('express'),
app = express(),
http = require('http').Server(app),
io = require('socket.io')(http);
http.listen(process.env.PORT || 5000, function(){
console.log('listening on *:5000');
});
创建该服务器后,我们将拥有io
类,该类允许设置一个以socket
为参数的回调。 使用此socket
对象,我们可以在用户的浏览器和服务器之间创建连接。
io.on('connection', function(socket) {
console.log('a user connected');
socket.on('disconnect', function(){
console.log('user disconnected');
});
});
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
在浏览器中,客户端链接到服务器,调用io
函数,该函数返回用于连接的socket
:
var socket = io("http://pubsub-example-with-backbone.herokuapp.com/");
话虽如此,让我们创建一个简单的通信,使数据和指令可以跨越网桥。
var socket = io("http://pubsub-example-with-backbone.herokuapp.com/")
// retrieve all nodes already stored in the server
socket.emit('retrieve-all-nodes')
$("button#add-new-node")
.on('click', function () {
socket.emit('add-node', {}, function (obj) {
console.log(obj)
})
})
socket.on('node-added', function (node) {
var $nodes = $("ul#nodes").append(`
<li id="${node.id}">
<span>${node.id}</span>
<button>x</button>
</li>
`)
$nodes
.find(`li#${node.id} button`)
.on('click', function () {
socket.emit('remove-node', node)
})
})
socket.on('node-removed', function (node) {
$("ul#nodes").find(`#${node.id}`).remove()
})
有了此代码,我们就可以构建以下演示 :
请参阅CodePen上的SitePoint( @SitePoint )的Pen mVRYMW 。
如果您想了解有关Socket.IO和Express的更多信息,建议您阅读以下文章:
- MEAN堆栈简介
- 使用Express 4创建RESTful API
- 构建一个由Node.js支持的Chatroom Web App:Node,MongoDB和Socket
- 使用Socket.IO的聊天应用程序
Backbone.js与Socket.IO
在本节中我将告诉你一个例子说明如何使用Socket.IO与Backbone.js的:
var MyView = Backbone.View.extend({
el: '#my-backbone-app',
events: {
'click button#add-new-node': 'addNewNode'
},
initialize: function (options) {
var view = this
view.socket = io("http://pubsub-example-with-backbone.herokuapp.com/")
view.socket.emit('retrieve-all-nodes')
view.model = new MyModel()
view.socket.on('node-added', function (node) {
var $node = $(`
<li>
<span>${node.id}</span>
<button>x</button>
</li>
`)
view.model.set(node.id, $node)
view.$el.find("ul#nodes").append($node)
$node.on('click', function () {
view.socket.emit('remove-node', node)
})
})
view.socket.on('node-removed', function (node) {
view.model.get(node.id).remove()
view.model.unset(node.id, {})
})
console.log('view initialized')
},
addNewNode: function () {
this.socket.emit('add-node', {}, function (obj) {
console.log(obj)
})
}
})
结果如下:
请参阅CodePen上的SitePoint( @SitePoint )提供的Pen QydXwo 。
带Backbone.js的PubSub
PubSub是异步消息传递范例。 它提供的功能使我们避免了耦合。 耦合是指一组代码彼此高度依赖时,这意味着如果一段代码发生更改,则需要对使用此段代码的所有内容进行更新。
PubSub是具有同步解耦的模式。 它使用事件系统,就像广播的工作方式一样:广播广播( 发布 ),任何人都可以收听( 订阅 )。 此外,您可以直接在共享的广播电台上发布消息,而不必直接与其他对象交谈。 该事件系统允许我们定义事件,这些事件可以传递包含订户所需值的参数。 Backbone.js使此事件系统的实现非常简单。 您只需要通过以下方式将Backbone.Events
混合到一个空对象中:
var EventChannel = _.extend({}, Backbone.Events);
此时,您可以使用标准trigger
和on
方法来发布和订阅消息:
var socket = io("http://pubsub-example-with-backbone.herokuapp.com/")
var MyPubSub = $.extend({}, Backbone.Events)
MyPubSub.on('disconnect', function () {
console.warn('disconnected')
})
socket.on('node-added', function (node) {
MyPubSub.trigger('node-added', node)
})
socket.on('node-removed', function (node) {
MyPubSub.trigger('node-removed', node)
})
MyPubSub.on('retrieve-all-nodes', function () {
socket.emit('retrieve-all-nodes')
})
MyPubSub.on('add-node', function (node, cb) {
socket.emit('add-node', node, function (obj) {
if (cb) {
node.id = obj.id
cb(node)
}
})
})
MyPubSub.on('remove-node', function (node) {
if (node && node.id) {
socket.emit('remove-node', node)
}
})
这样,您现在就可以从我们的Backbone View中删除socket.io
。
var MyView = Backbone.View.extend({
el: '#my-backbone-app',
events: {
'click button#add-new-node': 'addNewNode'
},
initialize: function (options) {
var view = this
view.model = new MyModel()
MyPubSub.on('node-added', function (node) {
var $node = $(`
<li>
<span>${node.id}</span>
<button>x</button>
</li>
`)
view.model.set(node.id, $node)
view.$el.find("ul#nodes").append($node)
$node.on('click', function () {
MyPubSub.trigger('remove-node', node)
})
})
MyPubSub.on('node-removed', function (node) {
view.model.get(node.id).remove()
view.model.unset(node.id, {})
})
MyPubSub.trigger('retrieve-all-nodes')
console.log('view initialized')
},
addNewNode: function () {
MyPubSub.trigger('add-node', {}, function (obj) {
console.log(obj)
})
}
})
目的是避免模块之间的依赖性。 每个模块可以具有一个频道,例如广播事件的广播电台(发布者),其他任何模块都可以收听希望接收通知的事件(订阅者)。
获得的结果如下:
请参阅CodePen上的SitePoint( @SitePoint )的Pen gPgNpz 。
图形可视化示例
我们的图形可视化在客户端使用两个模块:一个用于绘制有向图,另一个用于存储和获取数据。 图形绘制模块使用名为Force Editor的工具。 该模块在代码中称为ForceView
,可让我们以简单直观的方式将图形的节点定位在二维空间中。 我们称为DBaaS
的存储模块使用Socket.IO启用Web客户端和服务器之间的实时双向通信。 他们, ForceView和DBaaS都不了解其他任何东西。 他们的行为都是孤立的。
这两个模块均以发布/订阅样式设置,以避免依赖。 他们使用事件系统的方式与广播工作相同,广播站广播(发布),无线电接收器收听(订阅)。 每个模块都可以在自己的频道上触发事件,而不必直接与另一个模块进行对话,而是将消息发布到共享的“ 无线电台 ”上,而另一个模块也可以侦听其他任何频道上的事件。
这里唯一的依赖关系是每个具有非常小的API的无线电信道。 重要的是通道将触发哪个消息,并确保系统正确响应事件。 如果他们触发事件并给出正确的信息,则系统将整体运行。 查看下面的图像,以查看这些模块中的每个模块正在发出哪些事件。
骨干视图充当ForceView和DBaaS之间的中介。 这使我们可以将所有内容分解为可用的小片段,然后使这些小片段完美地协同工作。 这样,代码变得更易于理解和易于维护。
例如,如果我们只想对它进行一点自定义以使其符合特定的口味,那么我们可以轻松地选择任何模块并以自己喜欢的方式对其进行更改。 我们可以用其他图库代替图可视化,例如jqPlot , Dracula , ArborJS , sigmajs , RaphaelJS 等等 。 或者我们可以使用任何实时数据库,例如Firebase , Appbase , Neo4j , TitanDB等。好消息是我们只需要更改一个文件即可迁移到另一个库。 下图说明了骨干视图与这两个模块之间的交互。
请注意,我们没有使用任何数据库。 数据正在存储在内存中。 解耦代码的方式使我们可以连接到任何类型的数据库。
在本地运行图可视化示例
完整代码可在GitHub上获得 。 您可以克隆存储库或下载代码 。
gitclone https: //github.com/sitepoint-editors/pubsub-example-with-backbone.git
然后从控制台执行npm install
以安装所有依赖项。
接下来,执行node server.js
以启动应用程序。
使用浏览器访问http:// localhost:5000以查看正在运行的应用程序。 如果您只想查看实际的应用程序,可以在此处找到一个演示 。
结论
完蛋了! 我们只是使用Backbone的内置功能来实现PubSub模式。 此外,我们使用此模式实时表示和存储图形数据,其中数据在用户之间进行了精美的同步。 如您所见,在一个很好的示例中,我们混合了一些有趣的概念,以查看解耦的代码段协同工作。
现在的下一步是自定义它,并将数据存储在数据库中,而不是存储在内存中。 但是我们可能会在即将发表的一篇文章中讨论自定义。
请在下面的部分中随意分享您的评论。
翻译自: https://www.sitepoint.com/build-a-web-app-with-backbone-js-and-socket-io/
backbone.js