什么是双向绑定?
我已经读了很多,骨干不做双向绑定,但我不完全明白这个概念。
有人可以给我一个MVC代码库中的双向绑定是如何工作的,以及它如何不与Backbone?
双向绑定只是意味着:
- 当模型中的属性得到更新时,UI也是如此。
- 当UI元素得到更新时,更改会传播回模型。
Backbone没有#2的“烘焙”实现(尽pipe你可以使用事件监听器来做)。 像Knockout这样的其他框架可以自动连接双向绑定 。
在Backbone中,通过将视图的“渲染”方法绑定到模型的“更改”事件,可以轻松实现#1。 要实现#2,还需要在input元素中添加一个更改侦听器,并在处理程序中调用model.set
。
这是一个在Backbone中设置双向绑定的小提琴 。
双向绑定意味着影响模型的任何与数据相关的更改会立即传播到匹配的视图,并且在视图中进行的任何更改(例如,由用户) 立即反映在底层模型中。 当应用程序数据发生变化时,UI也会发生变化,反之亦然。
这是构buildWeb应用程序的一个非常稳固的概念,因为它使得“Model”抽象成为在应用程序中随处使用的安全的primefaces数据源。 比方说,如果绑定到视图的模型发生了变化,那么无论如何 ,它的匹配UI(视图)都会反映出来 。 而UI(视图)的匹配部分可以安全地用作收集用户input/数据的手段,从而保持应用程序数据是最新的。
从发展的angular度来看,一个好的双向绑定实现显然应该使模型和一些视图之间的这种联系尽可能简单。
因此,说Backbone不支持双向绑定是非常不真实的 :虽然不是框架的核心function,但是使用Backbone的事件可以很简单地执行。 对于简单的情况,它花费了几个明确的代码行; 对于更复杂的绑定可能会变得非常危险。 这里是一个简单的例子(未经testing的代码,只是为了说明而写):
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(未经testing的代码,见上):
<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}
总而言之,几乎所有的“主stream”JS框架都支持双向绑定。 其中一些,如骨干,确实需要一些额外的工作,使其工作顺利 ,但这些都是相同的,不强制执行一个特定的方式来开始。 所以这真的是关于你的心态。
另外,您可能对Flux感兴趣, Flux是Web应用程序的不同架构,通过循环模式来促进单向绑定。 它基于在任何数据更改时快速全面地重新呈现UI组件的概念,以确保内聚性,并使代码/数据stream更易于推理。 在同样的趋势中,您可能需要检查MVI(Model-View-Intent)的概念,例如Cycle 。
McGarnagle有一个很好的答案,你会想要接受他的,但是我想我会提到(因为你问了)数据绑定是如何工作的。
通常通过触发事件来实现,只要数据发生改变,然后导致监听器(例如UI)被更新。
双向绑定通过这样做两次,需要小心以确保您不会停留在事件循环(事件更新导致另一个事件被触发)中。
我会把这个评论,但它变得相当长…
其实emberjs
支持双向绑定,这是一个JavaScript MVC框架最强大的function之一。 您可以在其用户指南中查看binding
。
对于emberj来说,创build双向绑定是通过创build一个新的属性,并在末尾绑定stringBinding,然后从全局范围指定一个path:
App.wife = Ember.Object.create({ householdIncome: 80000 }); App.husband = Ember.Object.create({ householdIncomeBinding: 'App.wife.householdIncome' }); App.husband.get('householdIncome'); // 80000 // Someone gets raise. App.husband.set('householdIncome', 90000); App.wife.get('householdIncome'); // 90000
请注意,绑定不会立即更新。 Ember等待所有应用程序代码在同步更改前完成运行,因此您可以根据需要多次更改绑定属性,而无需担心在值为瞬态时同步绑定的开销。
希望这有助于延长select的原始答案。
值得一提的是,有许多不同的解决scheme提供双向绑定,并且非常好地播放。
我有一个愉快的经验与这个模型联编程序 – https://github.com/theironcook/Backbone.ModelBinder 。 这给出了合理的默认值,但很多模型属性的自定义jqueryselect器映射到input元素。
在github上有一个更加扩展的主干扩展/插件列表