我读过很多关于 Backbone 不做双向绑定的文章,但我并不完全理解这个概念。
有人可以给我一个示例,说明两种方式的绑定如何在 MVC 代码库中工作以及它如何不适用于 Backbone?
原文由 Chris M 发布,翻译遵循 CC BY-SA 4.0 许可协议
双向绑定意味着任何影响模型的数据相关更改都会 立即传播 到匹配的视图,并且在视图中所做的任何更改(例如,由用户)会 立即反映 在底层模型中.当应用程序数据发生变化时,用户界面也会发生变化,反之亦然。
这是在其上构建 Web 应用程序的一个非常可靠的概念,因为它使“模型”抽象成为一个安全的原子数据源,可以在应用程序中的任何地方使用。比如说,如果绑定到视图的模型发生变化,那么它的匹配 UI 部分(视图)将反映出来, _无论发生什么_。并且匹配的 UI(视图)可以安全地用作收集用户输入/数据的手段,从而使应用程序数据保持最新。
从开发人员的角度来看,一个好的双向绑定实现显然应该使模型和某些视图之间的这种连接尽可能简单。
说 Backbone 不 支持 双向绑定是完全不正确的:虽然这不是框架的核心功能,但可以使用 Backbone 的事件非常简单地执行。对于简单的情况,它会花费几行明确的代码;并且对于更复杂的绑定可能变得非常危险。这是一个简单的案例(未经测试的代码,只是为了说明而即时编写):
Model = Backbone.Model.extend
defaults:
data: ''
View = Backbone.View.extend
template: _.template("Edit the data: <input type='text' value='<%= data %>' />")
events:
# Listen for user inputs, and edit the model.
'change input': @setData
initialize: (options) ->
# Listen for model's edition, and trigger UI update
@listenTo @model, 'change:data', @render
render: ->
@$el.html @template(@model.attributes)
@
setData: (e) =>
e.preventDefault()
@model.set 'data', $(e.currentTarget).value()
model: new Model()
view = new View {el: $('.someEl'), model: model}
这是原始 Backbone 应用程序中非常典型的模式。如您所见,它需要相当数量的(相当标准的)代码。
AngularJS 和其他一些替代方案( Ember 、 Knockout ……)提供双向绑定作为第一个公民功能。他们在某些 DSL 下抽象出许多边缘案例,并尽最大努力将双向绑定集成到他们的生态系统中。我们的示例在 AngularJS 中看起来像这样(未经测试的代码,见上文):
<div ng-app="app" ng-controller="MainCtrl">
Edit the data:
<input name="mymodel.data" ng-model="mymodel.data">
</div>
angular.module('app', [])
.controller 'MainCtrl', ($scope) ->
$scope.mymodel = {data: ''}
比较短!
但是,请注意,Backbone 也 确实存在 一些 成熟 的双向绑定扩展(按照原始的、主观的复杂性递减顺序): Epoxy 、 Stickit 、 ModelBinder ……
例如,Epoxy 的一件很酷的事情是它允许您在模板 (DOM) 或视图实现 (JavaScript) 中声明您的绑定(模型属性 <-> 视图的 DOM 元素)。有些人非常不喜欢向 DOM/模板添加“指令”(例如 AngularJS 所需的 ng-* 属性,或 Ember 的数据绑定属性)。
以 Epoxy 为例,可以将原始的 Backbone 应用程序改造成这样的东西(…):
Model = Backbone.Model.extend
defaults:
data: ''
View = Backbone.Epoxy.View.extend
template: _.template("Edit the data: <input type='text' />")
# or, using the inline form: <input type='text' data-bind='value:data' />
bindings:
'input': 'value:data'
render: ->
@$el.html @template(@model.attributes)
@
model: new Model()
view = new View {el: $('.someEl'), model: model}
总而言之,几乎所有“主流”JS 框架都支持双向绑定。其中一些,例如 Backbone,确实需要做一些额外的工作才能使其 顺利 运行,但这些都是相同的,一开始就没有强制执行特定的方法。所以这真的是关于你的心态。
此外,您可能对 Flux 感兴趣,这是一种不同的 Web 应用程序架构,通过循环模式促进单向绑定。它基于在任何数据更改时快速、整体地重新呈现 UI 组件的概念,以确保内聚性并更容易推理代码/数据流。在同样的趋势下,您可能想检查 MVI (Model-View-Intent) 的概念,例如 Cycle 。
原文由 chikamichi 发布,翻译遵循 CC BY-SA 3.0 许可协议
13 回答13.1k 阅读
7 回答2.3k 阅读
3 回答1.4k 阅读✓ 已解决
6 回答1.4k 阅读✓ 已解决
2 回答1.5k 阅读✓ 已解决
3 回答1.5k 阅读✓ 已解决
6 回答1.2k 阅读
双向绑定只是意味着:
Backbone 没有#2 的“内置”实现(尽管您当然可以使用事件侦听器来实现)。其他框架 (如 Knockout)会自动连接双向绑定。
在 Backbone 中,您可以通过将视图的“render”方法绑定到其模型的“change”事件来轻松实现#1。要实现#2,您还需要向输入元素添加一个更改侦听器,并在处理程序中调用
model.set
。这是一个在 Backbone 中设置了双向绑定的小提琴。