Bacaan yang Disarankan:
Menerapkan pengikatan data dua arah JS yang sangat sederhana
MVVM adalah model pengembangan yang sangat populer untuk front-end web. Menggunakan MVVM dapat membuat kode kami lebih fokus pada berurusan dengan logika bisnis daripada peduli tentang operasi DOM. Saat ini, kerangka kerja MVVM yang terkenal termasuk Vue, Avalon, React, dll. Kerangka kerja ini memiliki keunggulannya sendiri, tetapi ide implementasinya kira -kira sama: pengikatan data + tampilan refresh. Karena penasaran dan kemauan untuk berjuang, saya juga menulis perpustakaan MVVM paling sederhana (MVVM.JS) di sepanjang arah ini, dengan total lebih dari 2.000 baris kode. Penamaan dan penggunaan instruksi mirip dengan Vue. Di sini saya akan membagikan prinsip -prinsip implementasi dan ide -ide organisasi kode saya.
Ide menyortir
MVVM secara konseptual merupakan pola yang benar -benar memisahkan pandangan dari logika data, dan ViewModel adalah fokus dari seluruh pola. Untuk mengimplementasikan ViewModel, Anda perlu mengaitkan model data (model) dan tampilan (tampilan). Seluruh ide implementasi dapat diringkas menjadi 5 poin:
Menerapkan kompiler untuk memindai dan mengekstrak instruksi untuk setiap simpul elemen;
Menerapkan parser untuk menguraikan instruksi pada elemen, yang dapat memperbarui maksud instruksi ke DOM melalui fungsi refresh (modul yang mungkin secara khusus bertanggung jawab untuk melihat menyegarkan mungkin diperlukan di tengah). Misalnya, ketika mem-parsing node <p v-show = "isShow"> </p>, pertama-tama dapatkan nilai isshow dalam model, dan kemudian ubah node.style.display menurut isShow untuk mengontrol tampilan dan menyembunyikan elemen;
Menerapkan pengamat dapat menghubungkan fungsi refresh dari setiap instruksi dalam parser dengan bidang yang sesuai dengan model;
Menerapkan pengamat untuk memantau perubahan nilai semua bidang objek, dan begitu perubahan terjadi, nilai terbaru dapat diperoleh dan panggilan balik pemberitahuan dapat dipicu;
Gunakan pengamat untuk membangun pemantauan model di pengamat. Ketika nilai dalam model berubah, pemantauan dipicu. Setelah pengamat mendapatkan nilai baru, ia memanggil fungsi penyegaran yang terkait pada Langkah 2, yang dapat mencapai tujuan menyegarkan tampilan saat data berubah.
Contoh Efek
Pertama, mari kita lihat contoh penggunaan akhir, yang mirip dengan instantiasi kerangka kerja MVVM lainnya:
<Div id = "Mobile-list"> <h1 v-text = "title"> </h1> <ul> <li v-for = "item in brand"> <b v-text = "item.name"> </b> <span v-show = "showrank"> peringkat: {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{span/span> </Li> </Li> </Li> Document.QuerySelector ('#Mobile-List'); var vm = mvvm baru (elemen, {'judul': 'Daftar seluler', 'showrank': true, 'brands': [{'name': 'apple', 'rank': 1}, {'nama': 'galaksi', 'peringkat': 2}, {'nama' 3}]}); vm.set ('title', 'Daftar peringkat seluler 3 teratas'); // => <h1> Daftar peringkat seluler teratas </h1>Divisi Modul
Saya membagi MVVM menjadi lima modul untuk diimplementasikan: Kompiler Modul Kompilasi, Parser, Lihat Pembaruan Modul Refresh, Pengamat Modul Berlangganan Data, dan Pengamat Modul Mendengarkan Data. Proses dapat dijelaskan secara singkat sebagai: Setelah kompiler mengkompilasi perintah, informasi instruksi diserahkan ke parser untuk parsing. Parser memperbarui nilai awal dan berlangganan pengamat untuk perubahan data. Observer memantau perubahan data dan kemudian memberinya kembali ke pengamat. Pengamat memberi tahu pembaruan hasil perubahan dan menemukan fungsi refresh yang sesuai untuk menyegarkan tampilan.
Proses di atas ditunjukkan pada gambar:
Berikut ini adalah deskripsi prinsip -prinsip dasar implementasi dari lima modul ini (kode hanya diposting pada bagian -bagian utama, silakan pergi ke github saya untuk implementasi lengkap)
1. Kompiler Modul Kompilasi
Tanggung jawab kompiler terutama untuk memindai dan mengekstrak instruksi untuk setiap simpul elemen. Karena proses kompilasi dan penguraian akan melintasi seluruh pohon simpul berkali -kali, untuk meningkatkan efisiensi kompilasi, dalam konstruktor MVVM, pertama -tama mengubah elemen menjadi salinan fragmen dokumen. Objek kompilasi adalah fragmen dokumen ini dan tidak boleh menjadi elemen target. Setelah semua node dikompilasi, fragmen dokumen ditambahkan kembali ke simpul asli asli.
vm.complieElement mengimplementasikan pemindaian dan ekstraksi instruksi dari semua node elemen:
vm.compileElement = function (fragmen, root) {var node, childnodes = fragment.childnodes; // pindai node anak untuk (var i = 0; i <childnodes.length; i ++) {node = childnodes [i]; if (this.hasdirective (node) {node. Pindai simpul anak dari simpul anak if (node.childnodes.length) {this.compileElement (node, false);}} // pindai node anak if (root) if (root) {this.compileallnodes ();}}}Metode VM.Compileallnodes akan mengkompilasi setiap node dalam hal ini. $ Uncompilenodes (serahkan informasi instruksi ke parser). Setelah menyusun node, itu akan dihapus dari antrian cache. Pada saat yang sama, periksa ini. $ Uncompilenodes.length saat panjang === 0, itu berarti semua kompilasi selesai. Anda dapat menambahkan fragmen dokumen ke simpul asli.
2. Parser Modul Parsing Instruksi
Ketika kompiler kompiler mengekstrak instruksi dari setiap node, itu dapat dikirim ke parser untuk parsing. Setiap instruksi memiliki metode parsing yang berbeda. Semua instruksi hanya perlu melakukan dua hal: satu adalah memperbarui nilai data ke tampilan (keadaan awal), dan yang lainnya adalah berlangganan fungsi refresh ke pemantauan perubahan model. Di sini kami menggunakan parsing v-teks sebagai contoh untuk menggambarkan metode analisis umum suatu arahan:
parser.parsevText = function (node, model) {// Dapatkan nilai awal yang ditentukan dalam model var text = this. $ model [model]; // Perbarui teks node.textcontent = teks; // fungsi refresh yang sesuai, // pembaruan. {node.textContent = last; // Updater.upDateNoDetextContent (node, teks);});}3. Pengamat Modul Berlangganan Data
Dalam contoh sebelumnya, Watcher menyediakan metode menonton untuk berlangganan perubahan data. Satu parameter adalah model bidang model dan yang lainnya adalah fungsi callback. Fungsi panggilan balik dipicu melalui pengamat. Nilai baru nilai terakhir dan lama sudah diteruskan dalam parameter. Setelah pengamat mendapatkan nilai baru, ia dapat menemukan panggilan balik yang sesuai (fungsi refresh) dari model untuk memperbarui tampilan. Fungsi model dan penyegaran adalah hubungan satu-ke-banyak, yaitu model dapat memiliki banyak fungsi callback (fungsi refresh) yang menanganinya, misalnya: V-text = "title" dan v-html = "title" Instruksi berbagi bidang model data.
Tambahkan Langganan Data ke Metode Implementasi Watcher.Watch adalah:
watcher.watch = function (bidang, panggilan balik, konteks) {var callbacks = this. $ watchcallbacks; if (! Object.hasownproperty.call (ini. $ Model, field)) {console.warn ('Field:' + field + 'tidak ada di model!'); return;} // buat array cache = callback {calls] (return;} // membuat array cache = callback {{{{} field {{field {{o) [];} // cache callbacks [field] .push ([callback, context]);}Ketika bidang bidang model data berubah, Watcher memicu semua panggilan balik dalam array cache yang telah berlangganan ke lapangan.
4. Pengamat Modul Pemantauan Data
Observer adalah fondasi inti dari seluruh implementasi MVVM. Saya membaca sebuah artikel yang mengatakan bahwa OO (Object.observe) akan menyalakan revolusi pengikatan data dan membawa pengaruh besar ke front-end. Sayangnya, draft ES7 telah meninggalkan OO! Tidak ada dukungan browser saat ini! Untungnya, ada juga objek.
// mencegat metode get and atur dari properti prop dari objek objek.definepropery (objek, prop, {get: function () {return this.getValue (objek, prop);}, set: function (newValue) {var oldvalue = this.getValue (objek, prop); if (newValue! == oldValue = this.getValue (objek, prop); if (newValue! prop); // pemicu perubahan callback this.triggerchange (prop, newValue, oldvalue);}}});Lalu ada pertanyaan lain: Bagaimana cara memantau operasi array (push, shift, dll.)? Semua kerangka kerja MVVM diimplementasikan dengan menulis ulang prototipe array:
Observer.RewRiteArrayMethods = function (array) {var self = this; var arrayproto = array.prototype; var arraymethods = objek.create (arrayproto); var metode = 'push | pop | shift | unshift | splice | sort | reverse'.split (' | '); methods.foreach (function (metode) {object.defineproperty (arrayMethods, method, function () {var i = arguments.length; var orisinal = arrayproto [metode]; var args = array baru (i) (i-) {args [i] = arguments [i];} var hasil (i-) {args [i] = arguments [i];} var resultch = original (i--) {args [i] = arguments [i];} var resultch = original (i--) {args [i] = arguments [i];} var resultch = original (i--) {args [i] = arguments [i];} var resultch = original. metode); hasil pengembalian;});}); array .__ proto__ = arraymethods;}Metode implementasi ini dirujuk dari VUE. Saya pikir itu digunakan dengan sangat baik, tetapi atribut panjang array tidak dapat didengarkan, jadi di MVVM, operasi array.
5. Lihat Pembaruan Modul Refresh
Updater adalah yang termudah di antara lima modul, Anda hanya perlu bertanggung jawab atas fungsi refresh yang sesuai dengan setiap instruksi. Setelah serangkaian melemparkan dan meninggalkan hasil akhir ke pembaruan untuk tampilan atau pembaruan acara, misalnya, fungsi refresh v-teks adalah:
Updater.UpDateNoDetextContent = function (node, text) {node.textContent = text;}Fungsi Refresh V-Bind: Gaya:
Updater.upDateNodestyle = fungsi (node, properti, nilai) {node.style [propperty] = value;}Implementasi pengikatan data dua arah
Ikatan data dua arah dari elemen bentuk adalah salah satu fitur terbesar dari MVVM:
Faktanya, prinsip implementasi fungsi magis ini juga sangat sederhana. Hanya ada dua hal yang harus dilakukan: satu adalah memperbarui nilai formulir ketika data berubah, dan yang lainnya adalah memperbarui data ketika nilai formulir berubah, sehingga nilai data terikat pada nilai formulir.
Perubahan data untuk memperbarui nilai formulir dapat dengan mudah dilakukan dengan menggunakan modul pengamat yang disebutkan di atas:
watcher.watch (model, fungsi (terakhir, lama) {input.value = last;}); 'Untuk memperbarui data dalam perubahan formulir, Anda hanya perlu mendengarkan formulir yang layak untuk mengubah acara secara real time dan memperbarui bidang yang sesuai dari model data:
var model = this. $ model; input.addeventListenr ('ubah', function () {model [field] = this.value;}); 'Formulir Radio, kotak centang, dan pilih lainnya adalah prinsip yang sama.
Di atas, seluruh proses dan ide implementasi dasar dari setiap modul telah dijelaskan. Pertama kali saya memposting artikel di komunitas, keterampilan ekspresi bahasa saya tidak terlalu bagus. Jika ada kata -kata yang salah dan hal -hal buruk yang ditulis, saya harap semua orang dapat mengkritik dan memperbaikinya!
Kesimpulan
Saya mencoba mvvm.js sederhana ini karena saya menggunakan vue.js dalam proyek kerangka kerja saya, tetapi saya hanya menggunakan sistem instruksinya. Banyak fungsi hanya digunakan sekitar seperempat. Saya pikir itu akan cukup untuk hanya mengimplementasikan pengikatan data dan pandangan-refresh. Akibatnya, saya tidak menemukan perpustakaan JavaScript seperti itu, jadi saya membuat roda seperti itu sendiri.
Meskipun fungsi dan stabilitas jauh lebih sedikit daripada kerangka kerja MVVM seperti Vue, dan implementasi kode mungkin relatif kasar, banyak pengetahuan telah ditambahkan dengan membangun roda ini ~ kemajuan terletak pada lemparan!
Saat ini, MVVM.JS saya hanya mengimplementasikan fungsi paling dasar. Saya akan terus meningkatkan dan memperkuatnya di masa depan. Jika Anda tertarik, silakan diskusikan dan tingkatkan bersama ~