Saya memiliki pengaturan nested-View yang bisa agak dalam di aplikasi saya. Ada banyak cara yang bisa saya pikirkan untuk menginisialisasi, merender, dan menambahkan sub-view, tapi saya bertanya-tanya apa praktik umum itu.
Berikut adalah beberapa yang pernah saya pikirkan:
initialize : function () {
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
},
render : function () {
this.$el.html(this.template());
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
Pro: Anda tidak perlu khawatir tentang mempertahankan pesanan DOM yang tepat dengan menambahkan. Tampilan diinisialisasi sejak awal, jadi tidak banyak yang bisa dilakukan sekaligus dalam fungsi render.
Kekurangan: Anda dipaksa untuk mendelegasikan kembali Acara (), yang mungkin mahal? Fungsi render tampilan orangtua berantakan dengan semua rendering subview yang perlu terjadi? Anda tidak memiliki kemampuan untuk mengatur tagName
elemen-elemen, sehingga templat perlu mempertahankan tagNames yang benar.
Cara lain:
initialize : function () {
},
render : function () {
this.$el.empty();
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
this.$el.append(this.subView1.render().el, this.subView2.render().el);
}
Pro: Anda tidak perlu mendelegasikan kembali acara. Anda tidak perlu templat yang hanya berisi tempat penampung kosong dan tagName Anda sudah kembali ditentukan oleh tampilan.
Cons: Anda sekarang harus memastikan untuk menambahkan hal-hal dalam urutan yang benar. Render tampilan orangtua masih berantakan oleh rendering subview.
Dengan sebuah onRender
acara:
initialize : function () {
this.on('render', this.onRender);
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
},
render : function () {
this.$el.html(this.template);
//other stuff
return this.trigger('render');
},
onRender : function () {
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
Pro: Logika subview sekarang dipisahkan dari metode tampilan render()
.
Dengan sebuah onRender
acara:
initialize : function () {
this.on('render', this.onRender);
},
render : function () {
this.$el.html(this.template);
//other stuff
return this.trigger('render');
},
onRender : function () {
this.subView1 = new Subview();
this.subView2 = new Subview();
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
Saya telah mencampur dan mencocokkan sekelompok praktik berbeda di semua contoh ini (sangat menyesal tentang hal itu), tetapi apa saja yang akan Anda pertahankan atau tambahkan? dan apa yang tidak akan kamu lakukan?
Ringkasan praktik:
- Instantiate subview di
initialize
atau dirender
? - Melakukan semua logika render tampilan sub-view di
render
atau dionRender
? - Gunakan
setElement
atauappend/appendTo
?
sumber
close
metode dan metodeonClose
yang membersihkan anak-anak, tetapi saya hanya ingin tahu tentang cara membuat instance dan membuat mereka di tempat pertama.delete
di JS tidak sama dengandelete
dari C ++. Kata kunci dengan nama sangat buruk jika Anda bertanya kepada saya.Jawaban:
Saya biasanya melihat / menggunakan beberapa solusi berbeda:
Solusi 1
Ini mirip dengan contoh pertama Anda, dengan beberapa perubahan:
render()
disebut SETELAH elemen tampilan dalam telah ditempatkan ke dalam DOM, yang membantu jikarender()
metode tampilan dalam Anda menempatkan / mengukur sendiri pada halaman berdasarkan posisi / ukuran elemen lain (yang merupakan kasus penggunaan umum, menurut pengalaman saya)Solusi 2
Solusi 2 mungkin terlihat lebih bersih, tetapi telah menyebabkan beberapa hal aneh dalam pengalaman saya dan telah mempengaruhi kinerja secara negatif.
Saya biasanya menggunakan Solusi 1, karena beberapa alasan:
render()
metode merekaPerlu diingat bahwa jika Anda menginisialisasi
new View()
setiap kalirender()
dipanggil, inisialisasi itu akandelegateEvents()
tetap memanggil . Jadi itu tidak harus menjadi "penipu", seperti yang telah Anda ungkapkan.sumber
Ini adalah masalah abadi dengan Backbone dan, dalam pengalaman saya, tidak ada jawaban yang memuaskan untuk pertanyaan ini. Saya berbagi rasa frustrasi Anda, terutama karena ada sedikit panduan meskipun betapa umum kasus penggunaan ini. Yang mengatakan, saya biasanya pergi dengan sesuatu yang mirip dengan contoh kedua Anda.
Pertama-tama, saya akan mengabaikan apa pun yang mengharuskan Anda untuk mendelegasikan kembali acara. Model tampilan yang digerakkan oleh acara Backbone adalah salah satu komponen yang paling penting, dan kehilangan fungsionalitas itu hanya karena aplikasi Anda non-sepele akan meninggalkan rasa tidak enak di mulut programmer mana pun. Jadi goreskan nomor satu.
Mengenai contoh ketiga Anda, saya pikir ini hanyalah akhir-run sekitar praktik rendering konvensional dan tidak menambah banyak makna. Mungkin jika Anda melakukan pemicu peristiwa aktual (yaitu, bukan "
onRender
" acara yang dibuat-buat ), akan lebih baik jika hanya mengikat acararender
itu sendiri. Jika Anda merasarender
menjadi sulit dan rumit, Anda memiliki terlalu sedikit subview.Kembali ke contoh kedua Anda, yang mungkin lebih kecil dari tiga kejahatan. Berikut adalah contoh kode yang diambil dari Recipes With Backbone , ditemukan pada halaman 42 dari edisi PDF saya:
Ini hanya pengaturan yang sedikit lebih canggih daripada contoh kedua Anda: mereka menentukan satu set fungsi,
addAll
danaddOne
, yang melakukan pekerjaan kotor. Saya pikir pendekatan ini bisa diterapkan (dan tentu saja saya menggunakannya); tapi itu masih meninggalkan aftertaste yang aneh. (Maafkan semua metafora lidah ini.)Sampai pada titik Anda menambahkan dalam urutan yang benar: jika Anda benar-benar menambahkan, tentu saja itu adalah batasan. Tetapi pastikan Anda mempertimbangkan semua skema templating yang mungkin. Mungkin Anda sebenarnya ingin elemen placeholder (mis., Kosong
div
atauul
) yang kemudian Anda dapatreplaceWith
elemen (DOM) baru yang memegang subview yang sesuai. Menambahkan bukan satu-satunya solusi, dan Anda pasti bisa mengatasi masalah pemesanan jika Anda sangat peduli, tetapi saya akan membayangkan Anda memiliki masalah desain jika itu membuat Anda tersandung. Ingat, subview dapat memiliki subview, dan harus jika pantas. Dengan begitu, Anda memiliki struktur mirip pohon, yang cukup bagus: setiap subview menambahkan semua subview, secara berurutan, sebelum tampilan induk menambahkan yang lain, dan seterusnya.Sayangnya, solusi # 2 mungkin adalah yang terbaik yang dapat Anda harapkan untuk menggunakan Backbone out-of-the-box. Jika Anda tertarik untuk memeriksa perpustakaan pihak ketiga, salah satu yang telah saya lihat (tetapi belum benar-benar memiliki waktu untuk bermain) adalah Backbone.LayoutManager , yang tampaknya memiliki metode yang lebih sehat untuk menambahkan subview. Namun, bahkan mereka telah memiliki perdebatan baru - baru ini tentang masalah yang serupa dengan ini.
sumber
model.bind('remove', view.remove);
- bukankah seharusnya Anda hanya melakukan itu dalam fungsi inisialisasi Pengangkatan untuk menjaga mereka terpisah?Terkejut ini belum disebutkan, tapi saya serius mempertimbangkan untuk menggunakan Marionette .
Ini memaksa struktur sedikit lebih untuk aplikasi Backbone, termasuk tampilan tertentu jenis (
ListView
,ItemView
,Region
danLayout
), menambahkan tepatController
dan banyak lagi.Ini adalah proyek tentang Github dan panduan hebat dari Addy Osmani dalam buku Backbone Fundamentals untuk membantu Anda memulai.
sumber
Saya memiliki, apa yang saya yakini, solusi yang cukup komprehensif untuk masalah ini. Ini memungkinkan model dalam koleksi untuk berubah, dan hanya tampilan yang dirender ulang (bukan seluruh koleksi). Ini juga menangani penghapusan tampilan zombie melalui metode close ().
Pemakaian:
sumber
Lihat mixin ini untuk membuat dan merender subview:
https://github.com/rotundasoftware/backbone.subviews
Ini adalah solusi minimalis yang mengatasi banyak masalah yang dibahas dalam utas ini, termasuk rendering order, tidak harus mendelegasikan kembali acara, dll. Perhatikan bahwa kasus tampilan koleksi (di mana setiap model dalam koleksi diwakili dengan satu Subview) adalah topik yang berbeda. Solusi umum terbaik yang saya ketahui tentang hal ini adalah CollectionView di Marionette .
sumber
Saya tidak terlalu menyukai solusi di atas. Saya lebih suka untuk konfigurasi ini daripada setiap tampilan harus secara manual melakukan pekerjaan dalam metode render.
views
bisa berupa fungsi atau objek yang mengembalikan objek definisi tampilan.remove
dipanggil, the.remove
anak-anak yang bersarang dari urutan paling bawah harus dipanggil (sepanjang jalan dari tampilan sub-sub-sub)Ini sebuah contoh:
sumber
Backbone sengaja dibangun sehingga tidak ada praktik "umum" dalam hal ini dan banyak masalah lainnya. Ini dimaksudkan untuk tidak dibuka sebanyak mungkin. Secara teoritis, Anda bahkan tidak perlu menggunakan templat dengan Backbone. Anda bisa menggunakan javascript / jquery dalam
render
fungsi tampilan untuk secara manual mengubah semua data dalam tampilan. Untuk membuatnya lebih ekstrem, Anda bahkan tidak perlu saturender
fungsi khusus . Anda bisa memiliki fungsi yang disebutrenderFirstName
yang memperbarui nama depan di dom danrenderLastName
yang memperbarui nama belakang di dom. Jika Anda mengambil pendekatan ini, akan jauh lebih baik dalam hal kinerja dan Anda tidak akan pernah harus mendelegasikan acara secara manual lagi. Kode tersebut juga akan masuk akal bagi seseorang yang membacanya (meskipun akan lebih panjang / berantakan).Namun, biasanya tidak ada kerugian untuk menggunakan template dan hanya menghancurkan dan membangun kembali seluruh tampilan dan subview pada setiap panggilan render, karena bahkan tidak terpikir oleh penanya untuk melakukan apa pun sebaliknya. Jadi itulah yang dilakukan kebanyakan orang untuk hampir setiap situasi yang mereka temui. Dan itulah mengapa kerangka kerja yang dikemukakan hanya menjadikan ini perilaku default.
sumber
Anda juga bisa menyuntikkan subview yang diberikan sebagai variabel ke template utama sebagai variabel.
pertama-tama render subview dan konversikan ke html seperti ini:
var subview1 = $(subview1.render.el).html(); var subview2 = $(subview2.render.el).html();
(dengan begitu Anda juga bisa secara dinamis merangkai tampilan seperti
subview1 + subview2
ketika digunakan dalam loop) dan kemudian meneruskannya ke template induk yang terlihat seperti ini:... some header stuff ... <%= sub1 %> <%= sub2 %> ... some footer stuff ...
dan menyuntikkannya akhirnya seperti ini:
this.$el.html(_.template(MasterTemplate, { sub1: subview1, sub2: subview2 } ));
Mengenai Acara dalam subview: Mereka kemungkinan besar harus terhubung di induk (masterView) dengan pendekatan ini tidak dalam subview.
sumber
Saya suka menggunakan pendekatan berikut yang juga memastikan untuk menghapus pandangan anak dengan benar. Ini adalah contoh dari buku karya Addy Osmani.
sumber
Tidak perlu mendelegasikan kembali acara karena mahal. Lihat di bawah:
sumber