นี่เป็นคำถามที่ยอดเยี่ยม Backbone นั้นยอดเยี่ยมเพราะไม่มีข้อสันนิษฐาน แต่มันก็หมายความว่าคุณต้อง (ตัดสินใจว่าจะทำอย่างไร) ให้ทำสิ่งต่าง ๆ เช่นนี้ด้วยตัวคุณเอง หลังจากตรวจสอบสิ่งต่าง ๆ ของตัวเองฉันพบว่าฉัน (ชนิด) ใช้การผสมผสานของสถานการณ์สมมติ 1 และสถานการณ์ 2 ฉันไม่คิดว่ามีสถานการณ์เวทย์มนตร์ที่ 4 อยู่เพราะเพียงพอทุกสิ่งที่คุณทำในสถานการณ์ 1 และ 2 จะต้องเป็น เสร็จแล้ว
ฉันคิดว่ามันจะง่ายที่สุดในการอธิบายวิธีที่ฉันชอบจัดการกับตัวอย่าง ว่าฉันมีหน้าง่าย ๆ นี้แบ่งออกเป็นมุมมองที่ระบุ:
สมมติว่า HTML คือหลังจากที่ถูกเรนเดอร์แล้วสิ่งนี้:
<div id="parent">
<div id="name">Person: Kevin Peel</div>
<div id="info">
First name: <span class="first_name">Kevin</span><br />
Last name: <span class="last_name">Peel</span><br />
</div>
<div>Phone Numbers:</div>
<div id="phone_numbers">
<div>#1: 123-456-7890</div>
<div>#2: 456-789-0123</div>
</div>
</div>
หวังว่ามันชัดเจนว่า HTML นั้นสอดคล้องกับไดอะแกรมอย่างไร
ParentView
ถือ 2 views เด็กInfoView
และPhoneListView
เช่นเดียวกับไม่กี่ divs พิเศษหนึ่งซึ่ง#name
จะต้องมีการตั้งค่าในบางจุด PhoneListView
เก็บมุมมองลูกของตัวเองอาร์เรย์ของPhoneView
รายการ
ดังนั้นคำถามที่แท้จริงของคุณ ฉันจัดการกับการเริ่มต้นและการแสดงผลแตกต่างกันไปตามประเภทการดู ฉันแบ่งมุมมองของฉันออกเป็นสองประเภทParent
มุมมองและChild
มุมมอง
ความแตกต่างระหว่างสิ่งเหล่านี้เป็นเรื่องง่ายParent
มุมมองจะเก็บมุมมองของเด็กไว้ในขณะที่Child
มุมมองไม่ได้ ดังนั้นในตัวอย่างของฉันParentView
และPhoneListView
มีParent
มุมมองในขณะที่InfoView
และPhoneView
รายการที่มีChild
มุมมอง
อย่างที่ฉันพูดไว้ก่อนหน้านี้ความแตกต่างที่ยิ่งใหญ่ที่สุดระหว่างสองหมวดหมู่คือเมื่อพวกเขาได้รับอนุญาตให้แสดงผล ในโลกที่สมบูรณ์แบบฉันต้องการParent
มุมมองที่จะแสดงเพียงครั้งเดียว มันขึ้นอยู่กับมุมมองลูกของพวกเขาที่จะจัดการกับการเรนเดอร์ใด ๆ เมื่อมีการเปลี่ยนแปลงรูปแบบ Child
ในทางกลับกันฉันอนุญาตให้แสดงผลอีกครั้งเมื่อใดก็ได้ที่ต้องการเนื่องจากไม่มีมุมมองอื่นที่ต้องพึ่งพา
ในรายละเอียดเพิ่มเติมเล็กน้อยสำหรับParent
มุมมองที่ฉันชอบinitialize
ฟังก์ชั่นของฉันที่จะทำบางสิ่ง:
- เริ่มต้นมุมมองของฉันเอง
- ทำให้มุมมองของฉันเอง
- สร้างและเริ่มต้นมุมมองลูก ๆ
- กำหนดให้เด็กแต่ละคนดูองค์ประกอบภายในมุมมองของฉัน (เช่น
InfoView
จะได้รับมอบหมาย#info
)
ขั้นตอนที่ 1 เป็นคำอธิบายที่ค่อนข้างดี
ขั้นตอนที่ 2 การเรนเดอร์เสร็จสิ้นเพื่อให้องค์ประกอบใด ๆ ที่มุมมองลูกพึ่งพานั้นมีอยู่ก่อนที่ฉันจะพยายามกำหนดมัน ด้วยการทำเช่นนี้ฉันรู้ว่าเด็กทุกคนevents
จะได้รับการตั้งค่าอย่างถูกต้องและฉันสามารถแสดงบล็อกของพวกเขาซ้ำได้หลายครั้งตามที่ฉันต้องการโดยไม่ต้องกังวลว่าจะต้องมอบหมายอะไรอีก ฉันไม่จริงrender
เด็ก ๆ initialization
มุมมองที่นี่ผมช่วยให้พวกเขาที่จะทำภายในของตัวเอง
ขั้นตอนที่ 3 และ 4 ได้รับการจัดการในเวลาเดียวกับที่ฉันผ่านเข้าไปel
ในขณะที่สร้างมุมมองเด็ก ฉันชอบที่จะส่งองค์ประกอบในที่นี่เพราะฉันรู้สึกว่าผู้ปกครองควรพิจารณาว่าเด็ก ๆ ได้รับอนุญาตให้ใส่เนื้อหาในมุมมองของตัวเองได้อย่างไร
สำหรับการเรนเดอร์ฉันพยายามทำให้มันค่อนข้างง่ายสำหรับParent
มุมมอง ฉันต้องการให้render
ฟังก์ชั่นไม่ทำอะไรมากไปกว่าการสร้างมุมมองพาเรนต์ ไม่มีการมอบหมายกิจกรรมไม่มีการแสดงผลมุมมองลูกไม่มีอะไร เพียงแค่เรนเดอร์ที่เรียบง่าย
บางครั้งมันก็ไม่ได้ผลเสมอไป เช่นในตัวอย่างด้านบน#name
องค์ประกอบจะต้องได้รับการอัปเดตทุกครั้งที่ชื่อในโมเดลเปลี่ยนแปลง อย่างไรก็ตามบล็อกนี้เป็นส่วนหนึ่งของParentView
เทมเพลตและไม่ได้รับการจัดการโดยChild
มุมมองเฉพาะดังนั้นฉันจึงแก้ไขมัน ฉันจะสร้างsubRender
ฟังก์ชั่นบางอย่างที่แทนที่เฉพาะเนื้อหาของ#name
องค์ประกอบและไม่ต้องทิ้ง#parent
องค์ประกอบทั้งหมด นี่อาจดูเหมือนแฮ็ค แต่ฉันพบว่ามันใช้งานได้ดีกว่าไม่ต้องกังวลเกี่ยวกับการเรนเดอร์ DOM ทั้งหมดและติดตั้งองค์ประกอบและสิ่งเหล่านี้อีกครั้ง ถ้าฉันต้องการทำให้มันสะอาดจริงๆฉันจะสร้างChild
มุมมองใหม่(คล้ายกับInfoView
) ที่จะจัดการกับ#name
บล็อก
ตอนนี้สำหรับChild
มุมมองแล้วinitialization
จะคล้ายกับParent
มุมมองโดยไม่สร้างChild
มุมมองเพิ่มเติมใด ๆ ดังนั้น:
- เริ่มต้นมุมมองของฉัน
- การตั้งค่าผูกมัดการฟังการเปลี่ยนแปลงใด ๆ กับรูปแบบที่ฉันสนใจ
- ทำให้มุมมองของฉัน
Child
el
มุมมองการแสดงผลยังเป็นง่ายมากเพียงแค่การแสดงผลและการตั้งค่าเนื้อหาของฉัน อีกครั้งไม่ยุ่งกับการมอบหมายหรืออะไรอย่างนั้น
นี่คือตัวอย่างรหัสของสิ่งที่ฉันParentView
อาจมีลักษณะ:
var ParentView = Backbone.View.extend({
el: "#parent",
initialize: function() {
// Step 1, (init) I want to know anytime the name changes
this.model.bind("change:first_name", this.subRender, this);
this.model.bind("change:last_name", this.subRender, this);
// Step 2, render my own view
this.render();
// Step 3/4, create the children and assign elements
this.infoView = new InfoView({el: "#info", model: this.model});
this.phoneListView = new PhoneListView({el: "#phone_numbers", model: this.model});
},
render: function() {
// Render my template
this.$el.html(this.template());
// Render the name
this.subRender();
},
subRender: function() {
// Set our name block and only our name block
$("#name").html("Person: " + this.model.first_name + " " + this.model.last_name);
}
});
คุณสามารถดูการใช้งานของฉันsubRender
ที่นี่ ด้วยการเปลี่ยนแปลงที่ถูกผูกไว้กับsubRender
แทนที่จะrender
ทำให้ฉันไม่ต้องกังวลเกี่ยวกับการระเบิดและสร้างใหม่ทั้งบล็อก
นี่คือตัวอย่างโค้ดสำหรับInfoView
บล็อก:
var InfoView = Backbone.View.extend({
initialize: function() {
// I want to re-render on changes
this.model.bind("change", this.render, this);
// Render
this.render();
},
render: function() {
// Just render my template
this.$el.html(this.template());
}
});
การผูกเป็นส่วนสำคัญที่นี่ การผูกเข้ากับโมเดลของฉันทำให้ฉันไม่ต้องกังวลกับการโทรหาrender
ตัวเอง หากรูปแบบการเปลี่ยนแปลงบล็อกนี้จะแสดงตัวเองอีกครั้งโดยไม่มีผลต่อมุมมองอื่น ๆ
สิ่งPhoneListView
นี้จะคล้ายกับParentView
คุณเพียงแค่ต้องใช้ตรรกะเพิ่มขึ้นเล็กน้อยทั้งในinitialization
และrender
ฟังก์ชั่นของคุณเพื่อจัดการคอลเลกชัน วิธีที่คุณจัดการกับคอลเลกชันนั้นขึ้นอยู่กับคุณ แต่อย่างน้อยคุณจะต้องฟังเหตุการณ์ของคอลเลกชันและตัดสินใจว่าคุณต้องการเรนเดอร์อย่างไร (ผนวก / ลบหรือเพียงแสดงบล็อกทั้งหมดอีกครั้ง) ฉันเป็นการส่วนตัวที่จะผนวกมุมมองใหม่และลบมุมมองเก่าออกไปไม่แสดงมุมมองทั้งหมดอีกครั้ง
PhoneView
จะเกือบจะเหมือนกันกับInfoView
เพียงการฟังการเปลี่ยนแปลงรูปแบบที่ใส่ใจเกี่ยวกับ
หวังว่านี่จะช่วยได้เล็กน้อยโปรดแจ้งให้เราทราบหากมีสิ่งที่ทำให้เกิดความสับสนหรือมีรายละเอียดไม่เพียงพอ