什么是双向绑定?

2022-08-30 01:34:30

我读过很多Backbone不做双向绑定,但我并不完全理解这个概念。

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


答案 1

双向绑定仅意味着:

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

Backbone 没有 #2 的“内置”实现(尽管您当然可以使用事件侦听器来执行此操作)。其他框架,如Knockout,会自动连接双向绑定


enter image description here


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

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


答案 2

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

这是一个非常可靠的概念,可以在其上构建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}

这是原始骨干应用程序中非常典型的模式。正如人们所看到的,它需要相当数量的(相当标准的)代码。

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的数据绑定属性)。

以环氧树脂为例,可以将原始的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(模型 - 视图 - 意图)的概念,例如Cycle