การผูกสองทางคืออะไร


173

ฉันได้อ่านล็อตที่ Backbone ไม่ได้ผูกมัดสองทาง แต่ฉันไม่เข้าใจแนวคิดนี้อย่างแน่นอน

ใครบางคนสามารถให้ฉันตัวอย่างของวิธีการผูกสองวิธีทำงานในรหัสฐาน MVC และวิธีที่ไม่ได้กับ Backbone?

คำตอบ:


249

การผูกสองทางหมายถึง:

  1. เมื่อคุณสมบัติในโมเดลได้รับการอัปเดต UI ก็เช่นกัน
  2. เมื่อองค์ประกอบ UI ได้รับการอัปเดตการเปลี่ยนแปลงจะแพร่กระจายกลับไปยังโมเดล

Backbone ไม่มีการนำ "baked-in" ไปใช้ # 2 (แม้ว่าคุณจะสามารถทำได้โดยใช้ Event listeners) กรอบอื่น ๆเช่นสิ่งที่น่าพิศวงไม่ลวดขึ้นสองทางผูกพันโดยอัตโนมัติ


ใน Backbone คุณสามารถบรรลุ # 1 ได้อย่างง่ายดายโดยผูกเมธอด "render" ของมุมมองกับเหตุการณ์ "เปลี่ยน" ของโมเดล เพื่อให้บรรลุ # 2 คุณจะต้องเพิ่มฟังการเปลี่ยนแปลงไปยังองค์ประกอบอินพุตและโทรmodel.setในตัวจัดการ

นี่คือซอที่มีการเชื่อมโยงสองทางใน Backbone


25
คำตอบนั้นชัดเจนมากเมื่อคุณเห็นมัน ขอบคุณมากที่สละเวลาเพื่อให้คำตอบและตัวอย่างที่ชัดเจน
Chris M

และด้วย Firebase มาพร้อม ... ฐานข้อมูลแบบ 3 มิติ -> มุมมองโมเดลฐานข้อมูล แค่คิดว่ามันค่อนข้างเรียบร้อย
Levi Fuller

กระชับและสั้น +1
Karan_powered_by_RedBull

46

สองทางผูกพันหมายถึงว่ามีการเปลี่ยนแปลงข้อมูลที่เกี่ยวข้องกับผลกระทบต่อรูปแบบที่มีการแพร่กระจายทันทีไปยังมุมมองที่ตรงกัน (s), และว่าการเปลี่ยนแปลงใด ๆ ที่ทำในมุมมอง (s) (พูดโดยผู้ใช้) จะมีผลทันทีในรูปแบบพื้นฐาน . เมื่อข้อมูลแอปมีการเปลี่ยนแปลง UI จะทำเช่นนั้นและตรงกันข้าม

นี่เป็นแนวคิดที่มั่นคงมากในการสร้างแอปพลิเคชันบนเว็บเพราะจะทำให้ "รุ่น" นามธรรมเป็นแหล่งข้อมูลอะตอมที่ปลอดภัยและใช้งานได้ทุกที่ภายในแอปพลิเคชัน ถ้ารูปแบบนั้นถูกผูกไว้กับมุมมองการเปลี่ยนแปลงชิ้นส่วนที่ตรงกันของ 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}

นี่เป็นรูปแบบที่ค่อนข้างธรรมดาในแอปพลิเคชั่น Backbone แบบดิบ อย่างที่เราเห็นมันต้องใช้โค้ด (มาตรฐานที่ค่อนข้างดี) ในปริมาณที่เหมาะสม

AngularJSและทางเลือกอื่น ๆ ( Ember , สิ่งที่น่าพิศวง …) ให้การผูกมัดแบบสองทางในฐานะพลเมืองคนแรก พวกเขาสรุปกรณีขอบจำนวนมากภายใต้ 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: ''}

ค่อนข้างสั้น!

แต่ทราบว่าบางเต็มเปี่ยมสองทางส่วนขยายที่มีผลผูกพันทำอยู่สำหรับหัวใจเช่นกัน (ในดิบเพื่อทัศนะของการลดความซับซ้อน): อีพ็อกซี่ , Stickit , ModelBinder ...

ยกตัวอย่างเช่นสิ่งที่ยอดเยี่ยมอย่างหนึ่งกับ Epoxy คือมันช่วยให้คุณสามารถประกาศการโยงของคุณ (แอตทริบิวต์ DOM <-> องค์ประกอบของมุมมองโมเดล) ทั้งในเทมเพลต (DOM) หรือภายในการนำมุมมองไปใช้ (JavaScript) บางคนไม่ชอบการเพิ่ม "directives" ลงใน DOM / เท็มเพลต (เช่นแอตทริบิวต์ ng- * ที่ AngularJS ต้องการหรือแอตทริบิวต์ data-bind ของ 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ซึ่งเป็นสถาปัตยกรรมที่แตกต่างกันสำหรับเว็บแอปพลิเคชันที่ส่งเสริมการเชื่อมโยงทางเดียวผ่านรูปแบบวงกลม มันขึ้นอยู่กับแนวคิดของการเรนเดอร์การแสดงผลส่วนประกอบของ UI ที่รวดเร็วและเป็นองค์รวมอย่างรวดเร็วเมื่อมีการเปลี่ยนแปลงข้อมูลใด ๆ เพื่อให้แน่ใจว่ามีการเชื่อมโยงกัน ในแนวโน้มเดียวกันคุณอาจต้องการตรวจสอบแนวคิดของ MVI (Model-View-เจตนา) ตัวอย่างเช่นวงจร


3
นักพัฒนาหลายคนโดยเฉพาะอย่างยิ่ง React / Flux ไม่ได้พิจารณาการผูกสองทางที่ปลอดภัยสำหรับการสร้างแอพขนาดใหญ่
Andy

28

McGarnagle มีคำตอบที่ยอดเยี่ยมและคุณจะต้องยอมรับเขา แต่ฉันคิดว่าฉันจะพูดถึง (ตั้งแต่คุณถาม) วิธีการทำงานของฐานข้อมูล

โดยทั่วไปแล้วจะนำไปใช้โดยการยิงเหตุการณ์เมื่อใดก็ตามที่มีการเปลี่ยนแปลงข้อมูลซึ่งจะทำให้ผู้ฟัง (เช่น UI) ได้รับการอัปเดต

การเชื่อมโยงแบบสองทางทำงานโดยการทำสองครั้งด้วยความระมัดระวังเล็กน้อยเพื่อให้แน่ใจว่าคุณจะไม่ติดขัดในลูปเหตุการณ์ (ที่การอัปเดตจากเหตุการณ์ทำให้เกิดเหตุการณ์อื่นที่จะถูกไล่ออก)

ฉันจะใส่ความคิดเห็นนี้ แต่มันก็ค่อนข้างยาว ...


2

ที่จริงemberjsสนับสนุนสองทางที่มีผลผูกพันซึ่งเป็นหนึ่งในคุณลักษณะที่มีประสิทธิภาพมากที่สุดสำหรับจาวาสคริปต์กรอบ MVC คุณสามารถตรวจสอบว่ามันพูดถึงbindingในคู่มือผู้ใช้

สำหรับ emberjs การสร้างการผูกสองทางคือการสร้างคุณสมบัติใหม่ด้วยการผูกสตริงที่ส่วนท้ายจากนั้นระบุพา ธ จากขอบเขตโกลบอล:

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 selector แบบกำหนดเองของคุณลักษณะของโมเดลกับองค์ประกอบอินพุต

มีรายการเพิ่มเติมของส่วนขยาย / ปลั๊กอินของกระดูกสันหลังบนgithub

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.