Ràng buộc hai chiều là gì?


173

Tôi đã đọc rất nhiều rằng Backbone không ràng buộc hai chiều nhưng tôi không hiểu chính xác khái niệm này.

Ai đó có thể cho tôi một ví dụ về cách liên kết hai cách hoạt động trong một cơ sở mã MVC và cách nó không hoạt động với Backbone?

Câu trả lời:


249

Ràng buộc hai chiều chỉ có nghĩa là:

  1. Khi các thuộc tính trong mô hình được cập nhật, giao diện người dùng cũng vậy.
  2. Khi các thành phần UI được cập nhật, các thay đổi sẽ được truyền trở lại mô hình.

Backbone không có triển khai "nướng" trong số 2 (mặc dù bạn chắc chắn có thể thực hiện bằng trình nghe sự kiện). Các khung khác như Knockout tự động kết nối hai chiều một cách tự động .


Trong Backbone, bạn có thể dễ dàng đạt được số 1 bằng cách ràng buộc phương thức "kết xuất" của chế độ xem với sự kiện "thay đổi" của mô hình. Để đạt được số 2, bạn cũng cần thêm một trình lắng nghe thay đổi vào thành phần đầu vào và gọi model.settrình xử lý.

Đây là một Fiddle với ràng buộc hai chiều được thiết lập trong Backbone.


25
Câu trả lời là rất rõ ràng một khi bạn nhìn thấy nó. Cảm ơn bạn rất nhiều vì đã dành thời gian để cung cấp một câu trả lời rõ ràng và ví dụ.
Chris M

Và với Firebase đi kèm ... cơ sở dữ liệu 3 chiều -> Xem, Mô hình, Cơ sở dữ liệu. Chỉ cần nghĩ rằng đó là khá gọn gàng.
Levi Fuller

Súc tích và ngắn gọn +1
Karan_powered_by_RedBull

46

Liên kết hai chiều có nghĩa là mọi thay đổi liên quan đến dữ liệu ảnh hưởng đến mô hình sẽ ngay lập tức được truyền đến (các) chế độ xem phù hợp và mọi thay đổi được thực hiện trong chế độ xem (giả sử) của người dùng) sẽ được phản ánh ngay lập tức trong mô hình bên dưới . Khi dữ liệu ứng dụng thay đổi, UI cũng vậy và ngược lại.

Đây là một khái niệm rất vững chắc để xây dựng một ứng dụng web trên hết, bởi vì nó làm cho "Mô hình" trừu tượng hóa thành một nguồn dữ liệu nguyên tử, an toàn để sử dụng ở mọi nơi trong ứng dụng. Giả sử, nếu một mô hình, bị ràng buộc với một khung nhìn, sẽ thay đổi, thì phần UI (khung nhìn) phù hợp của nó sẽ phản ánh điều đó, bất kể là gì . Và phần giao diện người dùng phù hợp (chế độ xem) có thể được sử dụng một cách an toàn như một phương tiện thu thập dữ liệu / dữ liệu người dùng, để duy trì cập nhật dữ liệu ứng dụng.

Việc triển khai ràng buộc hai chiều tốt rõ ràng sẽ làm cho kết nối này giữa một mô hình và một số khung nhìn đơn giản nhất có thể, theo quan điểm của người phát triển.

Sau đó, thật không đúng khi nói rằng Backbone không hỗ trợ ràng buộc hai chiều: mặc dù không phải là một tính năng cốt lõi của khung, nhưng nó có thể được thực hiện khá đơn giản bằng cách sử dụng Sự kiện của Backbone. Nó chi phí một vài dòng mã rõ ràng cho các trường hợp đơn giản; và có thể trở nên khá nguy hiểm cho các ràng buộc phức tạp hơn. Đây là một trường hợp đơn giản (mã chưa được kiểm tra, được viết khi đang bay chỉ vì mục đích minh họa):

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}

Đây là một mô hình khá điển hình trong một ứng dụng Backbone thô. Như người ta có thể thấy, nó đòi hỏi một lượng mã (khá chuẩn).

AngularJS và một số lựa chọn thay thế khác ( Ember , Knockout , ) cung cấp ràng buộc hai chiều như một tính năng công dân đầu tiên. Họ trừu tượng nhiều trường hợp cạnh trong một số DSL và cố gắng hết sức để tích hợp ràng buộc hai chiều trong hệ sinh thái của họ. Ví dụ của chúng tôi sẽ trông giống như thế này với AngularJS (mã chưa được kiểm tra, xem ở trên):

<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: ''}

Khá ngắn!

Nhưng, lưu ý rằng một số hoàn toàn chính thức mở rộng liên kết hai chiều vẫn tồn tại cho Backbone cũng (trong tình trạng thô, trật tự chủ quan của giảm độ phức tạp): Epoxy , Stickit , ModelBinder ...

Chẳng hạn, một điều thú vị với Epoxy là nó cho phép bạn khai báo các ràng buộc của mình (thuộc tính mô hình <-> phần tử DOM của khung nhìn) trong khuôn mẫu (DOM) hoặc trong triển khai chế độ xem (JavaScript). Một số người không thích thêm "chỉ thị" vào DOM / mẫu (chẳng hạn như các thuộc tính ng- * được yêu cầu bởi AngularJS hoặc thuộc tính liên kết dữ liệu của Ember).

Lấy Epoxy làm ví dụ, người ta có thể làm lại ứng dụng Backbone thô thành một cái gì đó như thế này (về):

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}

Nói chung, hầu hết tất cả các khung công tác JS "chính thống" đều hỗ trợ liên kết hai chiều. Một số trong số họ, chẳng hạn như Backbone, yêu cầu một số công việc bổ sung để làm cho nó hoạt động trơn tru , nhưng những cái đó giống nhau mà không thực thi một cách cụ thể để làm điều đó, để bắt đầu. Vì vậy, nó thực sự là về trạng thái tâm trí của bạn.

Ngoài ra, bạn có thể quan tâm đến Flux , một kiến ​​trúc khác cho các ứng dụng web thúc đẩy liên kết một chiều thông qua một mẫu hình tròn. Nó dựa trên khái niệm tái hiện nhanh chóng, toàn diện các thành phần UI khi có bất kỳ thay đổi dữ liệu nào để đảm bảo tính gắn kết và giúp dễ dàng suy luận về mã / dataflow. Trong cùng một xu hướng, bạn có thể muốn kiểm tra khái niệm MVI (Model-View-Intent), ví dụ Chu kỳ .


3
Nhiều nhà phát triển, đặc biệt là các nhà phát triển React / Flux không coi ràng buộc hai chiều là một mô hình an toàn để xây dựng các ứng dụng quy mô lớn.
Andy

28

McGarnagle có một câu trả lời tuyệt vời và bạn sẽ muốn chấp nhận câu trả lời của mình, nhưng tôi nghĩ tôi đã đề cập (vì bạn đã hỏi) cách thức hoạt động của cơ sở dữ liệu.

Nó thường được thực hiện bằng cách bắn các sự kiện bất cứ khi nào có thay đổi đối với dữ liệu, điều này sau đó khiến người nghe (ví dụ: UI) được cập nhật.

Liên kết hai chiều hoạt động bằng cách thực hiện hai lần, với một chút cẩn thận để đảm bảo rằng bạn không bị kẹt trong vòng lặp sự kiện (trong đó bản cập nhật từ sự kiện khiến một sự kiện khác bị hủy).

Tôi sẽ đưa nó vào một bình luận, nhưng nó đã trở nên khá dài ...


2

Trên thực tế emberjshỗ trợ ràng buộc hai chiều, đây là một trong những tính năng mạnh mẽ nhất cho khung MVC javascript. Bạn có thể kiểm tra xem nó đề cập đến bindingtrong hướng dẫn sử dụng của nó.

đối với emberjs, để tạo ràng buộc hai chiều bằng cách tạo một thuộc tính mới với chuỗi Binding ở cuối, sau đó chỉ định một đường dẫn từ phạm vi toàn cầu:

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

Lưu ý rằng các ràng buộc không cập nhật ngay lập tức. Ember đợi cho đến khi tất cả mã ứng dụng của bạn chạy xong trước khi đồng bộ hóa các thay đổi, vì vậy bạn có thể thay đổi một thuộc tính ràng buộc bao nhiêu lần tùy thích mà không phải lo lắng về chi phí liên kết đồng bộ hóa khi các giá trị là nhất thời.

Hy vọng nó sẽ giúp mở rộng câu trả lời ban đầu được chọn.


1

Đáng nói là có nhiều giải pháp khác nhau mang lại sự ràng buộc hai chiều và chơi thực sự độc đáo.

Tôi đã có một trải nghiệm thú vị với chất kết dính mô hình này - https://github.com/theironcook/Backbone.ModelBinder . cung cấp mặc định hợp lý nhưng có rất nhiều ánh xạ chọn bộ chọn tùy chỉnh của các thuộc tính mô hình cho các phần tử đầu vào.

Có một danh sách mở rộng hơn về các tiện ích mở rộng / plugin xương sống trên github

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.