什么是双向绑定?


173

我读过很多文章,Backbone不做双向绑定,但是我不太了解这个概念。

有人可以给我一个例子,说明MVC代码库中双向绑定如何工作以及Backbone如何不绑定吗?

Answers:


249

双向绑定仅意味着:

  1. 当模型中的属性更新时,UI也将更新。
  2. 更新UI元素后,更改将传播回模型。

骨干网没有#2的“内置”实现(尽管您当然可以使用事件侦听器来实现)。其他框架(例如Knockout)会自动绑定双向绑定


在Backbone中,您可以通过将视图的“ render”方法绑定到模型的“ change”事件来轻松实现#1。要实现#2,还需要在输入元素中添加一个更改侦听器,并model.set在处理程序中调用。

这是在Backbone中设置了双向绑定的小提琴


25
一旦看到答案,答案就非常痛苦。非常感谢您抽出宝贵的时间提供清晰的答案和示例。
克里斯M

Firebase附带了... 3向数据绑定->视图,模型,数据库。只是觉得那很整洁。
Levi Fuller

简洁而简短。+1
Karan_powered_by_RedBull

46

双向绑定意味着影响模型的任何与数据相关的更改都将立即传播到匹配的视图,并且对视图所做的任何更改(例如,由用户)都将立即反映在基础模型中。当应用程序数据更改时,UI也会更改,反之亦然。

这是在其上构建Web应用程序的一个非常扎实的概念,因为它使“模型”抽象成为安全的,原子的数据源,可以在应用程序中的任何地方使用。说,如果绑定到视图的模型发生了变化,那么无论如何,其匹配的UI(视图)都会反映出来。而且,可以将匹配的UI(视图)片段安全地用作收集用户输入/数据的一种方式,以保持应用程序数据为最新。

从开发人员的角度来看,良好的双向绑定实现显然应该使模型和某些视图之间的这种连接尽可能简单。

因此,说Backbone不支持双向绑定是非常不正确的:虽然不是框架的核心功能,但是可以使用Backbone的Events非常简单地执行它。对于简单的情况,它花费了几行明确的代码。对于更复杂的绑定会变得非常危险。这是一个简单的案例(未经验证的代码,仅出于说明目的而即时编写):

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和其他一些替代方法(EmberKnockout …)提供双向绑定作为第一个公民功能。他们将某些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也确实存在一些完善的双向绑定扩展(以降低复杂性的原始,主观顺序):EpoxyStickitModelBinder

例如,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感兴趣,Flux是Web应用程序的另一种体系结构,可通过圆形模式促进单向绑定。它基于在任何数据更改时快速,全面地重新呈现UI组件的概念,以确保内聚性并使其更易于推理代码/数据流。在同样的趋势下,您可能需要检查MVI(模型-视图-意图)的概念,例如Cycle


3
许多开发人员,尤其是React / Flux开发人员,并不认为双向绑定是构建大型应用程序的安全模式。
安迪2015年

28

McGarnagle有一个很好的答案,您将希望接受他,但是我想(由于您的询问)我想提一下数据绑定的工作原理。

通常是通过在数据发生更改时触发事件来实现的,这随后将导致侦听器(例如,UI)被更新。

双向绑定通过两次执行此工作,并要小心一点,以确保您不会陷入事件循环中(事件更新导致另一个事件被触发)。

我本来要对此发表评论,但是它已经相当长了...


2

实际上emberjs支持双向绑定,这是javascript MVC框架最强大的功能之一。您可以binding在其用户指南中查看提及的地方。

对于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

请注意,绑定不会立即更新。Ember等待所有应用程序代码完成运行,然后再同步更改,因此您可以根据需要多次更改绑定属性,而不必担心值是瞬态时同步绑定的开销。

希望它有助于扩展所选的原始答案。


1

值得一提的是,有许多不同的解决方案提供双向绑定,并且玩起来非常好。

我对这种模型活页夹-https: //github.com/theironcook/Backbone.ModelBinder有愉快的经验。这提供了合理的默认值,但还有许多将模型属性映射到输入元素的自定义jquery选择器映射。

github上有更多扩展的主干扩展/插件列表

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.