Silakan perlakukan pertanyaan ini sebagai sangat mendidik. Saya masih tertarik mendengar jawaban dan ide baru untuk mengimplementasikannya
tl; dr
Bagaimana saya menerapkan pengikatan data dua arah dengan JavaScript?
Mengikat data ke DOM
Dengan mengikat data ke DOM yang saya maksud misalnya, memiliki objek JavaScript a
dengan properti b
. Kemudian memiliki <input>
elemen DOM (misalnya), ketika elemen DOM berubah, a
berubah dan sebaliknya (yaitu, maksud saya pengikatan data dua arah).
Ini adalah diagram dari AngularJS tentang seperti apa ini:
Jadi pada dasarnya saya punya JavaScript mirip dengan:
var a = {b:3};
Kemudian elemen input (atau bentuk lain) seperti:
<input type='text' value=''>
Saya ingin nilai input menjadi a.b
nilai (misalnya), dan ketika teks input berubah, saya juga ingin a.b
mengubahnya. Ketika a.b
perubahan dalam JavaScript, input berubah.
Pertanyaan
Apa saja teknik dasar untuk mencapai ini dalam JavaScript biasa?
Secara khusus, saya ingin jawaban yang bagus untuk merujuk pada:
- Bagaimana cara mengikat bekerja untuk objek?
- Bagaimana mendengarkan perubahan dalam bentuk mungkin bekerja?
- Apakah mungkin dengan cara sederhana untuk hanya memodifikasi HTML pada tingkat templat? Saya ingin tidak melacak pengikatan dalam dokumen HTML itu sendiri tetapi hanya dalam JavaScript (dengan peristiwa DOM, dan JavaScript menjaga referensi ke elemen DOM yang digunakan).
Apa yang sudah saya coba?
Saya penggemar berat Kumis jadi saya mencoba menggunakannya untuk templating. Namun, saya mengalami masalah ketika mencoba melakukan pengikatan data itu sendiri karena Moustache memproses HTML sebagai string sehingga setelah saya mendapatkan hasilnya saya tidak memiliki referensi ke tempat objek di viewmodel saya. Satu-satunya solusi yang dapat saya pikirkan adalah memodifikasi string HTML (atau membuat pohon DOM) dengan atribut. Saya tidak keberatan menggunakan mesin templating yang berbeda.
Pada dasarnya, saya punya perasaan kuat bahwa saya memperumit masalah yang ada dan ada solusi sederhana.
Catatan: Tolong jangan memberikan jawaban yang menggunakan perpustakaan eksternal, terutama yang ribuan baris kode. Saya telah menggunakan (dan suka!) AngularJS dan KnockoutJS. Saya benar-benar tidak ingin jawaban dalam bentuk 'use framework x'. Secara optimal, saya ingin pembaca masa depan yang tidak tahu bagaimana menggunakan banyak kerangka kerja untuk memahami bagaimana menerapkan pengikatan data dua arah sendiri. Saya tidak mengharapkan jawaban yang lengkap , tetapi jawaban yang menyampaikan gagasan.
sumber
Jawaban:
Abstraksi yang memperbarui kedua objek
Saya kira ada teknik lain, tetapi pada akhirnya saya akan memiliki objek yang memegang referensi ke elemen DOM terkait, dan menyediakan antarmuka yang mengoordinasikan pembaruan untuk data sendiri dan elemen terkait.
Ini
.addEventListener()
menyediakan antarmuka yang sangat bagus untuk ini. Anda bisa memberinya objek yang mengimplementasikaneventListener
antarmuka, dan itu akan memanggil penangannya dengan objek tersebut sebagaithis
nilainya.Ini memberi Anda akses otomatis ke elemen dan data terkait.
Menentukan objek Anda
Warisan prototipe adalah cara yang bagus untuk menerapkan ini, meskipun tentu saja tidak diperlukan. Pertama, Anda akan membuat konstruktor yang menerima elemen Anda dan beberapa data awal.
Jadi di sini konstruktor menyimpan elemen dan data pada properti objek baru. Itu juga mengikat suatu
change
peristiwa dengan yang diberikanelement
. Yang menarik adalah ia melewatkan objek baru alih-alih fungsi sebagai argumen kedua. Tetapi ini saja tidak akan berhasil.Menerapkan
eventListener
antarmukaUntuk membuat ini berfungsi, objek Anda perlu menerapkan
eventListener
antarmuka. Semua yang diperlukan untuk mencapai ini adalah memberi objekhandleEvent()
metode.Di situlah warisan datang.
Ada banyak cara di mana hal ini dapat disusun, tetapi untuk contoh Anda mengoordinasikan pembaruan, saya memutuskan untuk membuat
change()
metode hanya menerima nilai, dan memilikihandleEvent
lulus itu bukan objek acara. Dengan cara inichange()
dapat dipanggil tanpa acara juga.Jadi sekarang, ketika
change
peristiwa itu terjadi, itu akan memperbarui elemen dan.data
properti. Dan hal yang sama akan terjadi ketika Anda memanggil.change()
program JavaScript Anda.Menggunakan kodenya
Sekarang Anda baru saja membuat objek baru, dan biarkan ia melakukan pembaruan. Pembaruan dalam kode JS akan muncul pada input, dan perubahan acara pada input akan terlihat oleh kode JS.
DEMO: http://jsfiddle.net/RkTMD/
sumber
Mustache.render(template,object)
, dengan asumsi saya ingin menyimpan objek yang disinkronkan dengan template (tidak khusus untuk Kumis), bagaimana saya akan melanjutkan tentang itu?input
yang memperbarui salah satu dari titik-titik itu, akan ada pemetaan dari input ke titik itu. Saya akan melihat apakah saya bisa memberikan contoh cepat.Template
konstruktor utama yang melakukan parsing, memegangMyCtor
objek yang berbeda , dan menyediakan antarmuka untuk memperbarui masing-masing oleh pengenalnya. Beri tahu saya jika Anda memiliki pertanyaan. :) EDIT: ... gunakan tautan ini sebagai gantinya ... Saya lupa bahwa saya memiliki peningkatan nilai input yang eksponensial setiap 10 detik untuk menunjukkan pembaruan JS. Ini membatasi itu.Jadi, saya memutuskan untuk melemparkan solusi saya sendiri ke dalam panci. Ini biola yang berfungsi . Perhatikan ini hanya berjalan di browser yang sangat modern.
Apa yang digunakannya
Implementasi ini sangat modern - ia membutuhkan (sangat) browser modern dan pengguna dua teknologi baru:
MutationObserver
s untuk mendeteksi perubahan dalam dom (pendengar acara juga digunakan)Object.observe
untuk mendeteksi perubahan pada objek dan memberitahukan dom. Bahaya, karena jawaban ini telah dituliskan Oo telah dibahas dan diputuskan oleh ECMAScript TC, pertimbangkan polyfill .Bagaimana itu bekerja
domAttribute:objAttribute
pemetaan - misalnyabind='textContent:name'
Solusinya
Ini
dataBind
fungsinya, perhatikan hanya 20 baris kode dan bisa lebih pendek:Berikut ini beberapa penggunaannya:
HTML:
JavaScript:
Ini biola yang berfungsi . Perhatikan bahwa solusi ini cukup umum. Object.observe dan pengamat mutasi tersedia.
sumber
obj.name
memiliki setter, ia tidak dapat diamati secara eksternal, tetapi harus disiarkan bahwa itu telah berubah dari dalam setter - html5rocks.com/en/tutorials/es7/observe/#toc-notifications - agak melempar kunci pas dalam karya untuk Oo () jika Anda ingin perilaku yang lebih kompleks dan saling bergantung menggunakan setter. Selain itu, ketikaobj.name
tidak dapat dikonfigurasi, mendefinisikan ulang penyetel itu (dengan berbagai trik untuk menambahkan pemberitahuan) juga tidak diperbolehkan - jadi obat generik dengan Oo () sepenuhnya dihapus dalam kasus tertentu.Saya ingin menambahkan ke preposter saya. Saya menyarankan pendekatan yang sedikit berbeda yang akan memungkinkan Anda untuk hanya menetapkan nilai baru ke objek Anda tanpa menggunakan metode. Namun harus dicatat bahwa ini tidak didukung oleh browser yang lebih tua dan IE9 masih memerlukan penggunaan antarmuka yang berbeda.
Yang paling penting adalah bahwa pendekatan saya tidak memanfaatkan peristiwa.
Setter dan Setter
Proposal saya memanfaatkan fitur getter dan setter yang relatif muda , terutama setter saja. Secara umum, mutator memungkinkan kita untuk "menyesuaikan" perilaku tentang bagaimana properti tertentu diberi nilai dan diambil.
Salah satu implementasi yang akan saya gunakan di sini adalah metode Object.defineProperty . Ia bekerja di FireFox, GoogleChrome dan - saya pikir - IE9. Belum menguji peramban lain, tetapi karena ini hanya teori ...
Bagaimanapun, ia menerima tiga parameter. Parameter pertama adalah objek yang Anda inginkan untuk mendefinisikan properti baru, yang kedua string yang menyerupai nama properti baru dan yang terakhir "objek deskriptor" yang menyediakan informasi tentang perilaku properti baru.
Dua deskriptor yang sangat menarik adalah
get
danset
. Contoh akan terlihat seperti berikut ini. Perhatikan bahwa menggunakan kedua ini melarang penggunaan 4 deskriptor lainnya.Sekarang memanfaatkan ini menjadi sedikit berbeda:
Saya ingin menekankan bahwa ini hanya berfungsi untuk browser modern.
Biola yang bekerja: http://jsfiddle.net/Derija93/RkTMD/1/
sumber
Proxy
objek Harmony :) Setters memang tampak seperti ide yang bagus, tetapi bukankah itu mengharuskan kita untuk memodifikasi objek yang sebenarnya? Juga, di samping catatan -Object.create
dapat digunakan di sini (sekali lagi, dengan asumsi browser modern yang diperbolehkan untuk parameter kedua). Juga, penyetel / pengambil dapat digunakan untuk 'memproyeksikan' nilai yang berbeda ke objek dan elemen DOM :). Saya ingin tahu apakah Anda memiliki wawasan tentang templating juga, yang tampaknya seperti tantangan nyata di sini, terutama untuk struktur dengan baik :)Proxy
, seperti yang Anda katakan.;) Saya mengerti tantangannya adalah untuk menjaga dua sifat yang berbeda disinkronkan. Metode saya menghilangkan salah satu dari keduanya.Proxy
akan menghilangkan kebutuhan untuk menggunakan getter / setter, Anda dapat mengikat elemen tanpa mengetahui properti apa yang mereka miliki. Yang saya maksudkan, adalah bahwa getter dapat mengubah lebih dari bindTo.value mereka dapat berisi logika (dan bahkan mungkin sebuah templat). Pertanyaannya adalah bagaimana cara mempertahankan pengikatan dua arah semacam ini dengan pola pikir? Katakanlah saya memetakan objek saya ke formulir, saya ingin mempertahankan elemen dan formulir yang disinkronkan dan saya bertanya-tanya bagaimana saya akan melanjutkan tentang hal semacam itu. Anda dapat memeriksa cara kerjanya pada knockout learn.knockoutjs.com/#/?tutorial=intro misalnyaSaya pikir jawaban saya akan lebih teknis, tetapi tidak berbeda karena yang lain menyajikan hal yang sama menggunakan teknik yang berbeda.
Jadi, hal pertama yang pertama, solusi untuk masalah ini adalah penggunaan pola desain yang dikenal sebagai "pengamat", itu memungkinkan Anda memisahkan data Anda dari presentasi Anda, membuat perubahan dalam satu hal disiarkan ke pendengar mereka, tetapi dalam hal ini itu dibuat dua arah.
Untuk cara DOM ke JS
Untuk mengikat data dari DOM ke objek js Anda dapat menambahkan markup dalam bentuk
data
atribut (atau kelas jika Anda memerlukan kompatibilitas), seperti ini:Dengan cara ini dapat diakses melalui js menggunakan
querySelectorAll
(atau teman lamagetElementsByClassName
untuk kompatibilitas).Sekarang Anda dapat mengikat acara mendengarkan perubahan dalam cara: satu pendengar per objek atau satu pendengar besar ke wadah / dokumen. Mengikat dokumen / wadah akan memicu acara untuk setiap perubahan yang dibuat di dalamnya atau itu anak, itu akan memiliki jejak memori yang lebih kecil tetapi akan menelurkan acara.
Kode akan terlihat seperti ini:
Untuk JS lakukan cara DOM
Anda akan membutuhkan dua hal: satu meta-objek yang akan menampung referensi elemen DOM penyihir diikat ke setiap objek / atribut js dan cara untuk mendengarkan perubahan pada objek. Pada dasarnya cara yang sama: Anda harus memiliki cara untuk mendengarkan perubahan pada objek dan kemudian mengikatnya ke simpul DOM, karena metadata objek Anda "tidak bisa", Anda akan memerlukan objek lain yang menyimpan metadata dengan cara bahwa nama properti memetakan ke properti objek metadata. Kode akan seperti ini:
Saya harap saya bisa membantu.
sumber
Object.observe
sebagai dukungan hanya tersedia di chrome untuk saat ini. caniuse.com/#feat=object-observeKemarin, saya mulai menulis cara saya sendiri untuk mengikat data.
Sangat lucu bermain dengannya.
Saya pikir itu indah dan sangat berguna. Setidaknya pada pengujian saya menggunakan firefox dan chrome, Edge juga harus bekerja. Tidak yakin tentang orang lain, tetapi jika mereka mendukung Proxy, saya pikir itu akan berhasil.
https://jsfiddle.net/2ozoovne/1/
Ini kodenya:
Kemudian, untuk mengatur, cukup:
Untuk saat ini, saya baru saja menambahkan ikatan nilai HTMLInputElement.
Beri tahu saya jika Anda tahu cara memperbaikinya.
sumber
Ada implementasi barebone yang sangat sederhana dari pengikatan data 2 arah dalam tautan ini "Pengikatan Data Dua Arah Mudah dalam JavaScript"
Tautan sebelumnya bersama dengan ide-ide dari knockoutjs, backbone.js dan agility.js, menyebabkan kerangka kerja MVVM yang ringan dan cepat ini, ModelView.js
berdasarkan jQueryyang bermain baik dengan jQuery dan saya penulis yang rendah hati (atau mungkin tidak begitu rendah hati).Mereproduksi kode sampel di bawah ini (dari tautan posting blog ):
Kode sampel untuk DataBinder
sumber
Mengubah nilai elemen dapat memicu peristiwa DOM . Pendengar yang merespons peristiwa dapat digunakan untuk menerapkan pengikatan data dalam JavaScript.
Sebagai contoh:
Berikut ini adalah kode dan demo yang menunjukkan bagaimana elemen DOM dapat diikat satu sama lain atau dengan objek JavaScript.
sumber
Bind input html apa pun
tentukan dua fungsi:
gunakan fungsinya:
sumber
Berikut adalah ide penggunaan
Object.defineProperty
yang secara langsung mengubah cara properti diakses.Kode:
Pemakaian:
biola: Di sini
sumber
Saya telah melalui beberapa contoh javascript dasar menggunakan onkeypress dan penangan event onchange untuk membuat tampilan mengikat ke js dan js kami untuk melihat
Berikut contoh plunker http://plnkr.co/edit/7hSOIFRTvqLAvdZT4Bcc?p=preview
sumber
sumber
Cara sederhana untuk mengikat variabel ke input (pengikatan dua arah) adalah dengan langsung mengakses elemen input di pengambil dan penyetel:
Dalam HTML:
Dan untuk menggunakan:
Cara yang lebih bagus untuk melakukan hal di atas tanpa pengambil / penyetel:
Menggunakan:
sumber
Ini sangat sederhana mengikat data dua arah dalam javascript vanilla ....
sumber
Terlambat ke pesta, terutama karena saya sudah menulis 2 lib terkait bulan / tahun yang lalu, saya akan menyebutkannya nanti, tetapi masih terlihat relevan bagi saya. Untuk membuatnya spoiler sangat pendek, teknologi pilihan saya adalah:
Proxy
untuk observasi modelMutationObserver
untuk pelacakan perubahan DOM (untuk alasan yang mengikat, bukan perubahan nilai)addEventListener
penangan biasaIMHO, selain OP, penting bahwa implementasi pengikatan data akan:
user.address.block
shift
,splice
dan serupa)Mempertimbangkan semua itu, menurut pendapat saya membuatnya tidak mungkin untuk hanya membuang beberapa baris JS. Saya sudah mencoba melakukannya sebagai pola daripada lib - tidak berhasil untuk saya.
Selanjutnya, setelah
Object.observe
dihapus, namun mengingat bahwa pengamatan model adalah bagian penting - seluruh bagian ini HARUS dipisah-pisahkan dengan lib lain. Sekarang ke pokok kepala sekolah tentang bagaimana saya mengambil masalah ini - persis seperti yang ditanyakan OP:Model (bagian JS)
Pandangan saya untuk observasi model adalah Proxy , ini adalah satu-satunya cara yang waras untuk membuatnya bekerja, IMHO. Fitur lengkap
observer
layaknya perpustakaan itu sendiri, jadi saya telah mengembangkanobject-observer
perpustakaan untuk tujuan tunggal itu.Model / s harus didaftarkan melalui beberapa API khusus, itulah titik di mana POJO berubah menjadi
Observable
s, tidak dapat melihat pintasan apa pun di sini. Elemen DOM yang dianggap sebagai pandangan terikat (lihat di bawah), diperbarui dengan nilai-nilai model pada awalnya dan kemudian pada setiap perubahan data.Tampilan (bagian HTML)
IMHO, cara terbersih untuk menyatakan ikatan, adalah melalui atribut. Banyak yang melakukan ini sebelumnya dan banyak yang akan melakukannya setelah itu, jadi tidak ada berita di sini, ini hanya cara yang tepat untuk melakukannya. Dalam kasus saya, saya menggunakan sintaks berikut:,
<span data-tie="modelKey:path.to.data => targerProperty"></span>
tetapi ini kurang penting. Apa yang penting bagi saya, tidak ada sintaks scripting yang kompleks dalam HTML - ini adalah salah, sekali lagi, IMHO.Semua elemen yang ditunjuk sebagai pandangan terikat harus dikumpulkan terlebih dahulu. Tampaknya bagi saya dari sisi kinerja tidak terelakkan untuk mengelola beberapa pemetaan internal antara model dan tampilan, tampaknya kasus yang tepat di mana memori + beberapa manajemen harus dikorbankan untuk menyimpan pencarian dan pembaruan runtime.
Pandangan diperbarui pada awalnya dari model, jika tersedia dan perubahan model kemudian, seperti yang kita katakan. Terlebih lagi, seluruh DOM harus diamati dengan cara
MutationObserver
untuk bereaksi (mengikat / mengikat) pada elemen yang ditambahkan / dihapus / diubah secara dinamis. Selanjutnya, semua ini, harus direplikasi ke dalam ShadowDOM (satu terbuka, tentu saja) agar tidak meninggalkan lubang hitam yang tidak terikat.Daftar spesifik memang bisa melangkah lebih jauh, tetapi menurut pendapat saya prinsip-prinsip utama yang akan membuat pengikatan data diimplementasikan dengan keseimbangan yang baik dari kelengkapan fitur dari satu dan kesederhanaan waras dari sisi lain.
Dan dengan demikian, selain yang
object-observer
disebutkan di atas, saya telah menulis jugadata-tier
perpustakaan, yang mengimplementasikan pengikatan data di sepanjang konsep yang disebutkan di atas.sumber
Banyak hal telah berubah banyak dalam 7 tahun terakhir, kami memiliki komponen web asli di sebagian besar browser sekarang. IMO inti masalahnya adalah berbagi status di antara elemen, begitu Anda memiliki hal yang sepele untuk memperbarui ui ketika keadaan berubah dan sebaliknya.
Untuk berbagi data antar elemen Anda bisa membuat kelas StateObserver, dan memperluas komponen web Anda dari itu. Implementasi minimal terlihat seperti ini:
biola di sini
Saya suka pendekatan ini karena:
data-
propertisumber