Dalam fikiran saya, ruang kepala untuk reka bentuk MVC adalah "Bagaimana saya memodelkan domain perniagaan saya? Bagaimanakah saya memodelkan proses berinteraksi dengan domain itu? Bagaimanakah saya memodelkan antara muka untuk memudahkan proses tersebut? ". Adalah pendapat saya bahawa ruang kepala ini tidak memudahkan reka bentuk komponen yang baik. Sebenarnya ia adalah bertentangan dengan bagaimana anda harus berfikir apabila anda berangkat untuk memecahkan antara muka ke dalam komponen yang boleh dikomposisikan. Sebaik -baiknya anda akan berakhir dengan aplikasi mikro. Paling teruk anda akan membina komponen Tuhan. Perkara terakhir yang anda mahu lakukan ialah memodelkan domain perniagaan anda sebagai komponen. Apa yang anda harus bertujuan untuk memodelkan adalah bahagian abstrak terkecil interaksi yang boleh anda terangkan.
Merancang untuk penggunaan semula
Sebagai contoh lain, jangan buat komponen carian bantuan jenis yang digunakan di mana-mana anda ingin membenarkan mencari sistem bantuan, membuat komponen input teks yang mencadangkan yang mengetahui tentang interaksi yang terlibat dalam menyediakan cadangan input. Kemudian buat komponen data API Carian Bantuan yang tahu bagaimana untuk menerima permintaan untuk data, berinteraksi dengan API Bantuan Carian dan hasil siaran. Sekarang ujian input teks yang anda sugeskan tidak memerlukan sebarang pengejaran API, dan apabila anda diminta menambah cadangan ke medan "tag", anda boleh menjatuhkan komponen input teks yang sedia ada anda, mengikat komponen data mudah yang bercakap ke API tag, dan selesai!
Untuk contoh konkrit, mari lihat pelaksanaan antara muka mudah sebagai komponen terpencil. Mockup berikut adalah pengekstrakan dari 99Designs 1-to-1 Projects System. Walaupun UI telah dipermudahkan secara drastik, JavaScript yang akan kami bina adalah kod pengeluaran dari laman web kami pada masa penulisan. Inilah wireframe:
di teras itu kita mempunyai tindakan setiap baris. Apabila tindakan itu dilakukan, kami ingin mengeluarkan baris dari senarai. Sudah kami telah menumpahkan pengetahuan domain khusus projek! Selanjutnya, kami mempunyai kiraan dengan berapa banyak item dalam setiap senarai. Untuk menahan skop artikel ini, kami mengandaikan setiap halaman untuk dijana sisi pelayan, dengan navigasi tab menyebabkan penyegaran halaman penuh. Memandangkan kita tidak perlu memaksa pergantungan pada JavaScript, butang tindakan kita akan menjadi elemen membentuk dengan pengendali acara yang akan secara tidak sengaja melaksanakan tindakan borang dan menyiarkan acara apabila ia selesai.
Berikut adalah beberapa HTML untuk satu baris projek:
Saya akan menggunakan penerbangan untuk membina komponen kami. Penerbangan pada masa ini adalah perpustakaan komponen JS lalai kami di 99Designs atas sebab -sebab yang saya digariskan dalam artikel SitePoint JavaScript sebelumnya.
<span><span><span><li</span>></span> </span> <span><span><span><a</span> href<span>="/projects/99"</span> title<span>="View project"</span>></span>Need sticker designs for XYZ Co.<span><span></a</span>></span> </span> <span><span><span><div</span> class<span>="project__actions"</span>></span> </span> <span><span><span><a</span> href<span>="/projects/99"</span> class<span>="button"</span>></span>View<span><span></a</span>></span> </span> <span><span><span><form</span> class<span>="action"</span> action<span>="/projects/99/archive"</span> method<span>="post"</span>></span> </span> <span><span><span><button</span>></span>Archive<span><span></button</span>></span> </span> <span><span><span></form</span>></span> </span> <span><span><span></div</span>></span> </span><span><span><span></li</span>></span></span>
Berikut adalah komponen asyncform kami untuk mengendalikan penyerahan borang dan menyiarkan acara:
kami mengekalkan dasar yang ketat untuk tidak menggunakan atribut kelas untuk JavaScript, jadi kami akan menambah atribut bentuk data-async ke borang tindakan kami, dan melampirkan komponen kami ke semua bentuk yang sepadan seperti SO:
<span>define(function(require) { </span> <span>'use strict'; </span> <span>var defineComponent = require('flight/lib/component'); </span> <span>function <span>AsyncForm</span>() { </span> <span>this.defaultAttrs({ </span> <span>broadcastEvent: 'uiFormProcessed' </span> <span>}); </span> <span>this.after('initialize', function() { </span> <span>this.on(this.node, 'submit', this.asyncSubmit.bind(this)); </span> <span>}); </span> <span>this.asyncSubmit = function(event) { </span> event<span>.preventDefault(); </span> $<span>.ajax({ </span> <span>'url': this.$node.attr('action'), </span> <span>'dataType': 'json', </span> <span>'data': this.$node.serializeArray(), </span> <span>'type': this.$node.attr('method') </span> <span>}).done(function(response<span>, data</span>) { </span> <span>this.$node.trigger(this.attr.broadcastEvent, data); </span> <span>}.bind(this)).fail(function() { </span> <span>// error handling excluded for brevity </span> <span>}); </span> <span>}; </span> <span>} </span> <span>return defineComponent(AsyncForm); </span><span>});</span>
<span><span><span><li</span>></span> </span> <span><span><span><a</span> href<span>="/projects/99"</span> title<span>="View project"</span>></span>Need sticker designs for XYZ Co.<span><span></a</span>></span> </span> <span><span><span><div</span> class<span>="project__actions"</span>></span> </span> <span><span><span><a</span> href<span>="/projects/99"</span> class<span>="button"</span>></span>View<span><span></a</span>></span> </span> <span><span><span><form</span> class<span>="action"</span> action<span>="/projects/99/archive"</span> method<span>="post"</span>></span> </span> <span><span><span><button</span>></span>Archive<span><span></button</span>></span> </span> <span><span><span></form</span>></span> </span> <span><span><span></div</span>></span> </span><span><span><span></li</span>></span></span>
Sekarang kita mempunyai keupayaan untuk melakukan tindakan, dan menyiarkan acara yang akan menyebarkan pokok Dom pada kejayaan. Langkah seterusnya adalah mendengar acara itu dan menghapuskan baris yang ia gelembung sehingga. Untuk itu kita boleh tanggal:
<span>define(function(require) { </span> <span>'use strict'; </span> <span>var defineComponent = require('flight/lib/component'); </span> <span>function <span>AsyncForm</span>() { </span> <span>this.defaultAttrs({ </span> <span>broadcastEvent: 'uiFormProcessed' </span> <span>}); </span> <span>this.after('initialize', function() { </span> <span>this.on(this.node, 'submit', this.asyncSubmit.bind(this)); </span> <span>}); </span> <span>this.asyncSubmit = function(event) { </span> event<span>.preventDefault(); </span> $<span>.ajax({ </span> <span>'url': this.$node.attr('action'), </span> <span>'dataType': 'json', </span> <span>'data': this.$node.serializeArray(), </span> <span>'type': this.$node.attr('method') </span> <span>}).done(function(response<span>, data</span>) { </span> <span>this.$node.trigger(this.attr.broadcastEvent, data); </span> <span>}.bind(this)).fail(function() { </span> <span>// error handling excluded for brevity </span> <span>}); </span> <span>}; </span> <span>} </span> <span>return defineComponent(AsyncForm); </span><span>});</span>
Sekali lagi kami menambah atribut yang boleh ditukar data ke baris projek kami, dan lampirkan komponen ke elemen baris:
<span>AsyncForm.attachTo('[data-async-form]');</span>
selesai! Dua komponen kecil dengan satu peristiwa masing -masing, dan kami telah mengendalikan tiga jenis tindakan dalam tiga bentuk kami dengan cara yang lemah. Hanya satu perkara yang tersisa, dan itulah kiraan kami pada setiap tab. Harus cukup mudah, semua yang kita perlukan adalah untuk menurunkan jumlah tab aktif oleh satu setiap kali baris dikeluarkan. Tetapi tunggu! Apabila projek aktif diarkibkan, kiraan yang diarkibkan perlu meningkat, dan apabila projek yang diarkibkan diaktifkan semula, kiraan aktif perlu meningkat. Pertama, buatlah komponen kiraan yang dapat menerima arahan untuk mengubah nombornya:
<span>define(function(require) { </span> <span>'use strict'; </span> <span>var defineComponent = require('flight/lib/component'); </span> <span>function <span>Removable</span>() { </span> <span>this.defaultAttrs({ </span> <span>'removeOn': 'uiFormProcessed' </span> <span>}); </span> <span>this.after('initialize', function() { </span> <span>this.on(this.attr.removeOn, this.remove.bind(this)); </span> <span>}); </span> <span>this.remove = function(event) { </span> <span>// Animate row removal, remove DOM node, teardown component </span> $<span>.when(this.$node </span> <span>.animate({'opacity': 0}, 'fast') </span> <span>.slideUp('fast') </span> <span>).done(function() { </span> <span>this.$node.remove(); </span> <span>}.bind(this)); </span> <span>}; </span> <span>} </span> <span>return defineComponent(Removable); </span><span>});</span>
kiraan kami akan diwakili dalam HTML sebagai sesuatu seperti 4 . Kerana kiraan mendengarkan peristiwa di peringkat dokumen, kami akan membuat NULL harta acaranya. Ini akan memaksa apa -apa penggunaannya untuk menentukan peristiwa yang harus didengar oleh contoh ini, dan menghalang secara tidak sengaja mempunyai beberapa contoh kiraan mendengar arahan pada peristiwa yang sama.
<span>Removable.attachTo('[data-removable]');</span>
Sekeping akhir teka -teki adalah mendapatkan contoh yang boleh ditanggalkan untuk membakar acara dengan pengubah suai ke kaunter masing -masing apabila mereka dikeluarkan. Kami pastinya tidak mahu gandingan antara komponen, jadi kami akan memberikan atribut yang boleh ditanggalkan yang merupakan pelbagai peristiwa untuk dibakar apabila ia dikeluarkan:
<span>define(function(require) { </span> <span>'use strict'; </span> <span>var defineComponent = require('flight/lib/component'); </span> <span>function <span>Count</span>() { </span> <span>this.defaultAttrs({ </span> <span>'event': null </span> <span>}); </span> <span>this.after('initialize', function() { </span> <span>this.on(document, this.attr.event, this.update.bind(this)); </span> <span>}); </span> <span>this.update = function(event<span>, data</span>) { </span> <span>this.$node.text( </span> <span>parseInt(this.$node.text(), 10) + data.modifier </span> <span>); </span> <span>} </span> <span>} </span> <span>return defineComponent(Count); </span><span>});</span>
sekarang gandingan antara kiraan dan boleh tanggal berlaku dalam skrip halaman khusus penggunaan di mana kami melampirkan komponen kami ke DOM:
<span>Count.attachTo( </span> <span>'[data-counter="active"]', </span> <span>{'event': 'uiActiveCountChanged'} </span><span>); </span> <span>Count.attachTo( </span> <span>'[data-counter="draft"]', </span> <span>{'event': 'uiDraftCountChanged'} </span><span>); </span> <span>Count.attachTo( </span> <span>'[data-counter="archived"]', </span> <span>{'event': 'uiArchivedCountChanged'} </span><span>);</span>
Misi dicapai. Kaunter kami tidak tahu apa -apa mengenai baris senarai projek kami, yang tidak mengetahui apa -apa bentuk di dalamnya. Dan tidak ada komponen yang sedikit pun direka bentuk di sekitar konsep senarai projek.
Pereka UX kami telah menegaskan bahawa lebih baik jika kami meminta pengesahan apabila seseorang cuba memadam draf, kerana tindakan ini tidak dapat dibatalkan. Tidak ada masalah, kita boleh menyiapkan komponen yang hanya itu:
<span>define(function(require) { </span> <span>'use strict'; </span> <span>var defineComponent = require('flight/lib/component'); </span> <span>function <span>Removable</span>() { </span> <span>this.defaultAttrs({ </span> <span>'removeOn': 'uiFormProcessed', </span> <span>'broadcastEvents': [ </span> <span>{'event': 'uiRemoved', 'data': {}} </span> <span>] </span> <span>}); </span> <span>this.after('initialize', function() { </span> <span>this.on(this.attr.removeOn, this.remove.bind(this)); </span> <span>}); </span> <span>this.remove = function(event) { </span> <span>// Broadcast events to notify the rest of the UI that this component has been removed </span> <span>this.attr.broadcastEvents.forEach(function(eventObj) { </span> <span>this.trigger(eventObj.event, eventObj.data); </span> <span>}.bind(this)); </span> <span>// Animate row removal, remove DOM node, teardown component </span> $<span>.when(this.$node </span> <span>.animate({'opacity': 0}, 'fast') </span> <span>.slideUp('fast') </span> <span>).done(function() { </span> <span>this.$node.remove(); </span> <span>}.bind(this)); </span> <span>}; </span> <span>} </span> <span>return defineComponent(Removable); </span><span>});</span>
Lampirkannya ke butang padam, dan kami mempunyai apa yang kami minta. Dialog mengesahkan akan memintas butang, dan membenarkan penyerahan borang jika pengguna memilih "OK". Kami tidak perlu mengubah komponen asyncform kami, kerana kami dapat menyusun komponen ini tanpa mengganggu satu sama lain. Dalam kod pengeluaran kami, kami juga menggunakan komponen singlesubmit pada butang tindakan yang memberikan maklum balas visual bahawa borang telah diserahkan dan menghalang pelbagai penyerahan.
Mudah -mudahan artikel ini telah menunjukkan bagaimana projek anda dapat mendapat manfaat daripada memecahkan antara muka ke dalam komponen yang boleh komposit. Manfaat penting reka bentuk komponen yang saya tidak dilindungi adalah kemudahan ujian terpencil mereka, jadi inilah komponen akhir bersama dengan ujian melati dan lekapan ujian HTML:
Jika anda mempunyai sebarang pertanyaan mengenai apa yang saya tutupi, sila minta butiran dalam komen dan saya akan melakukan yang terbaik untuk membantu.
Apakah peranan logik dalam pemikiran kritikal? pemikiran kritikal. Ia melibatkan keupayaan untuk membuat alasan dengan betul, untuk mendapatkan kesimpulan dari premis, untuk menilai tuntutan, dan untuk mengelakkan kesalahan atau kesilapan dalam penalaran. Maklumat atau idea yang kita sedang mempertimbangkan secara langsung berkaitan dengan isu atau masalah di tangan. Ia membantu kita untuk terus fokus dan mengelakkan gangguan atau maklumat yang tidak relevan.
Bagaimana saya dapat meningkatkan kejelasan pemikiran saya? kesederhanaan dan kesederhanaan dalam pemikiran dan ekspresi kita.
Atas ialah kandungan terperinci Berfikir dalam komponen. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!