Javascript 什么是双向绑定?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13504906/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is two way binding?
提问by Chris M
I have read lots that Backbone doesn't do two way binding but I don't exactly understand this concept.
我读过很多关于 Backbone 不做双向绑定的书,但我并不完全理解这个概念。
Could somebody give me an example of how two way binding works in an MVC codebase and how it does not with Backbone?
有人能给我一个例子,说明在 MVC 代码库中双向绑定是如何工作的,以及它在 Backbone 中是如何工作的吗?
回答by McGarnagle
Two-way binding just means that:
双向绑定只是意味着:
- When properties in the model get updated, so does the UI.
- When UI elements get updated, the changes get propagated back to the model.
- 当模型中的属性更新时,UI 也会更新。
- 当 UI 元素更新时,更改会传播回模型。
Backbone doesn't have a "baked-in" implementation of #2 (although you can certainly do it using event listeners). Other frameworks like Knockout do wire up two-way binding automagically.
Backbone 没有 #2 的“内置”实现(尽管您当然可以使用事件侦听器来实现)。其他框架(如 Knockout)会自动连接双向绑定。
In Backbone, you can easily achieve #1 by binding a view's "render" method to its model's "change" event. To achieve #2, you need to also add a change listener to the input element, and call model.setin the handler.
在 Backbone 中,您可以通过将视图的“render”方法绑定到其模型的“change”事件来轻松实现#1。为了实现#2,您还需要向输入元素添加一个更改侦听器,并model.set在处理程序中调用。
Here's a Fiddlewith two-way binding set up in Backbone.
回答by chikamichi
Two-way binding means that any data-related changes affecting the model are immediately propagatedto the matching view(s), and that any changes made in the view(s) (say, by the user) are immediately reflectedin the underlying model. When app data changes, so does the UI, and conversely.
双向绑定意味着影响模型的任何与数据相关的更改都会立即传播到匹配的视图,并且视图中所做的任何更改(例如,由用户)都会立即反映在底层模型中. 当应用程序数据发生变化时,UI 也会发生变化,反之亦然。
This is a very solid concept to build a web application on top of, because it makes the "Model" abstraction a safe, atomic data source to use everywhere within the application. Say, if a model, bound to a view, changes, then its matching piece of UI (the view) will reflect that, no matter what. And the matching piece of UI (the view) can safely be used as a mean of collecting user inputs/data, so as to maintain the application data up-to-date.
这是在其上构建 Web 应用程序的一个非常可靠的概念,因为它使“模型”抽象成为一个安全的原子数据源,可以在应用程序中的任何地方使用。比如说,如果绑定到视图的模型发生变化,那么无论发生什么,它的匹配 UI(视图)都会反映出来。并且匹配的 UI(视图)可以安全地用作收集用户输入/数据的手段,从而使应用程序数据保持最新。
A good two-way binding implementation should obviously make this connection between a model and some view(s) as simple as possible, from a developper point of view.
从开发人员的角度来看,一个好的双向绑定实现显然应该使模型和某些视图之间的这种连接尽可能简单。
It is then quite untrueto say that Backbone does not supporttwo-way binding: while not a core feature of the framework, it can be performed quite simply using Backbone's Events though. It costs a few explicit lines of code for the simple cases; and can become quite hazardous for more complex bindings. Here is a simple case (untested code, written on the fly just for the sake of illustration):
说 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}
This is a pretty typical pattern in a raw Backbone application. As one can see, it requires a decent amount of (pretty standard) code.
这是原始 Backbone 应用程序中非常典型的模式。正如人们所见,它需要相当数量的(相当标准的)代码。
AngularJSand some other alternatives (Ember, Knockout…) provide two-way binding as a first-citizen feature. They abstract many edge-cases under some DSL, and do their best at integrating two-way binding within their ecosystem. Our example would look something like this with AngularJS (untested code, see above):
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: ''}
Rather short!
比较短!
But, be aware that some fully-fledgedtwo-way binding extensions do existfor Backbone as well (in raw, subjective order of decreasing complexity): Epoxy, Stickit, ModelBinder…
但是,请注意,对于 Backbone 也确实存在一些成熟的双向绑定扩展(以原始的、主观的复杂性递减顺序):Epoxy、Stickit、ModelBinder……
One cool thing with Epoxy, for instance, is that it allows you to declare your bindings (model attributes <-> view's DOM element) either within the template (DOM), or within the view implementation (JavaScript). Some people strongly dislike adding "directives" to the DOM/template (such as the ng-* attributes required by AngularJS, or the data-bind attributes of Ember).
例如,Epoxy 的一件很酷的事情是,它允许您在模板 (DOM) 或视图实现 (JavaScript) 中声明您的绑定(模型属性 <-> 视图的 DOM 元素)。有些人非常不喜欢在 DOM/模板中添加“指令”(例如 AngularJS 所需的 ng-* 属性,或者 Ember 的 data-bind 属性)。
Taking Epoxy as an example, one can rework the raw Backbone application into something like this (…):
以 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}
All in all, pretty much all "mainstream" JS frameworks support two-way binding. Some of them, such as Backbone, do require some extra work to make it work smoothly, but those are the same which do not enforce a specific way to do it, to begin with. So it is really about your state of mind.
总而言之,几乎所有“主流”JS 框架都支持双向绑定。其中一些,例如 Backbone,确实需要一些额外的工作才能使其顺利运行,但这些都是相同的,它们并没有强制执行特定的方法来开始。所以这真的是关于你的心态。
Also, you may be interested in Flux, a different architecture for web applications promoting one-way binding through a circular pattern. It is based on the concept of fast, holistic re-rendering of UI components upon any data change to ensure cohesiveness and make it easier to reason about the code/dataflow. In the same trend, you might want to check the concept of MVI (Model-View-Intent), for instance Cycle.
此外,您可能对Flux感兴趣,这是一种用于通过循环模式促进单向绑定的 Web 应用程序的不同架构。它基于在任何数据更改时快速、全面地重新渲染 UI 组件的概念,以确保内聚性并使代码/数据流更容易推理。在相同的趋势中,您可能想要检查 MVI(模型-视图-意图)的概念,例如Cycle。
回答by Jeff
McGarnagle has a great answer, and you'll want to be accepting his, but I thought I'd mention (since you asked) how databinding works.
McGarnagle 有一个很好的答案,你会想要接受他的,但我想我会提到(因为你问过)数据绑定是如何工作的。
It's generally implemented by firing events whenever a change is made to the data, which then causes listeners (e.g. the UI) to be updated.
它通常通过在数据发生更改时触发事件来实现,然后会导致侦听器(例如 UI)更新。
Two-way binding works by doing this twice, with a bit of care taken to ensure that you don't wind up stuck in an event loop (where the update from the event causes another event to be fired).
双向绑定通过执行两次此操作来工作,并注意确保您不会陷入事件循环(事件的更新导致另一个事件被触发)。
I was gonna put this in a comment, but it was getting pretty long...
我想把它放在评论中,但它变得很长......
回答by weia design
Actually emberjssupports two-way binding, which is one of the most powerful feature for a javascript MVC framework. You can check it out where it mentioning bindingin its user guide.
实际上emberjs支持双向绑定,这是 javascript MVC 框架最强大的特性之一。您可以查看它binding在用户指南中提到的位置。
for emberjs, to create two way binding is by creating a new property with the string Binding at the end, then specifying a path from the global scope:
对于 emberjs,创建双向绑定是通过在末尾创建一个字符串 Binding 的新属性,然后从全局范围指定一个路径:
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
Note that bindings don't update immediately. Ember waits until all of your application code has finished running before synchronizing changes, so you can change a bound property as many times as you'd like without worrying about the overhead of syncing bindings when values are transient.
请注意,绑定不会立即更新。Ember 会等到所有应用程序代码都运行完毕后再同步更改,因此您可以根据需要多次更改绑定属性,而无需担心值是瞬态时同步绑定的开销。
Hope it helps in extend of original answer selected.
希望它有助于扩展所选的原始答案。
回答by Daniel
Worth mentioning that there are many different solutions which offer two way binding and play really nicely.
值得一提的是,有许多不同的解决方案提供了两种方式的绑定,并且播放效果非常好。
I have had a pleasant experience with this model binder - https://github.com/theironcook/Backbone.ModelBinder. which gives sensible defaults yet a lot of custom jquery selector mapping of model attributes to input elements.
我对这个模型绑定器有一个愉快的体验 - https://github.com/theironcook/Backbone.ModelBinder。它提供了合理的默认值,还提供了大量自定义 jquery 选择器将模型属性映射到输入元素。
There is a more extended list of backbone extensions/plugins on github
github上有更多扩展的主干扩展/插件列表

