Что такое двусторонняя привязка? - программирование

Что такое двусторонняя привязка?

Я читал много, что Backbone не выполняет двухстороннюю привязку, но я не совсем понимаю эту концепцию.

Может ли кто-нибудь дать мне пример того, как двусторонняя привязка работает в кодовой базе MVC и как она не работает с Backbone?

4b9b3361

Ответ 1

Двусторонняя привязка просто означает, что:

  • Когда свойства в модели обновляются, также пользовательский интерфейс.
  • Когда элементы пользовательского интерфейса обновляются, изменения распространяются обратно на модель.

Магистраль не имеет "запеченной" реализации # 2 (хотя вы, безусловно, можете сделать это с помощью прослушивателей событий). Другие фреймворки такие как Knockout, автоматически связывают двустороннюю привязку.


В Backbone вы можете легко достичь # 1, привязав метод "рендеринга" к его событию "изменение" модели. Чтобы достичь # 2, вам нужно также добавить прослушиватель изменений к элементу ввода и вызвать model.set в обработчике.

Здесь сценарий с двусторонней привязкой, установленный в Backbone.

Ответ 2

Двусторонняя привязка означает, что любые связанные с данными изменения, влияющие на модель, немедленно распространяются на соответствующие (ые) представления и что любые изменения, сделанные в представлении (точках зрения) (например, пользователем), немедленно отражаются в лежащей в основе модели. Когда данные приложения изменяются, пользовательский интерфейс и наоборот.

Это очень прочная концепция для создания веб-приложения поверх, потому что он делает абстракцию "Модель" безопасным, атомным источником данных для использования повсюду в приложении. Скажем, если модель, связанная с представлением, изменится, то ее соответствующий фрагмент пользовательского интерфейса (представление) будет отражать это, несмотря ни на что. И соответствующий фрагмент пользовательского интерфейса (вид) можно безопасно использовать в качестве средства сбора пользовательских входов/данных, чтобы поддерживать актуальность данных приложения.

Хорошая реализация двухсторонней привязки должна, очевидно, сделать эту связь между моделью и некоторыми представлениями максимально простой, с точки зрения разработки.

В то же время совершенно неверно говорить, что 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 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 вида) либо внутри шаблона (DOM), либо в рамках реализации представления (JavaScript). Некоторым людям очень не нравится добавлять "директивы" в DOM/template (такие как атрибуты ng- *, требуемые AngularJS, или атрибуты привязки данных 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, другая архитектура для веб-приложений, способствующих односторонней привязке по круговой схеме. Он основан на концепции быстрого целостного повторного рендеринга компонентов пользовательского интерфейса при любых изменениях данных, чтобы обеспечить согласованность и упростить рассуждение о коде/потоке данных. В той же тенденции вы можете проверить концепцию MVI (Model-View-Intent), например Cycle.

Ответ 3

МакГарнагл имеет отличный ответ, и вы захотите принять его, но я подумал, что я бы сказал (с тех пор как вы спросили), как работает привязка данных.

Обычно он реализуется путем запуска событий всякий раз, когда происходит изменение данных, что приводит к обновлению прослушивателей (например, пользовательского интерфейса).

Двусторонняя привязка работает, делая это дважды, с небольшим вниманием, чтобы убедиться, что вы не застряли в цикле событий (где обновление из события вызывает другое событие для запуска).

Я собирался поставить это в комментарии, но это было довольно долго...

Ответ 4

Фактически emberjs поддерживает двустороннюю привязку, которая является одной из самых мощных функций для javascript MVC framework. Вы можете проверить это, где упоминается 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 ждет, пока весь ваш код приложения не будет завершен до синхронизации изменений, поэтому вы можете изменить свойство привязки столько раз, сколько хотите, не беспокоясь об издержках привязки синхронизации, когда значения являются временными.

Надеюсь, что это поможет в расширении исходного ответа.

Ответ 5

Стоит упомянуть, что существует множество различных решений, которые предлагают двухстороннюю привязку и играют действительно красиво.

У меня был приятный опыт работы с этим связующим устройством - https://github.com/theironcook/Backbone.ModelBinder. который дает разумные значения по умолчанию, но еще множество настраиваемых селекторов jquery для атрибутов модели для элементов ввода.

Существует более расширенный список расширений/плагинов магистрали на github