Rumah > Artikel > hujung hadapan web > Melaksanakan pengikatan dua hala kemahiran javascript data_javascript dengan mudah
Pengikatan data dua hala bermakna apabila sifat objek berubah, UI yang sepadan boleh ditukar pada masa yang sama, dan begitu juga sebaliknya. Dalam erti kata lain, jika kita mempunyai objek pengguna yang mempunyai sifat nama, apabila anda menetapkan nilai baharu kepada nama pengguna, UI akan memaparkan nilai baharu. Begitu juga, jika UI mengandungi kotak input untuk nama pengguna, memasukkan nilai baharu akan menyebabkan sifat nama objek pengguna berubah dengan sewajarnya.
Banyak rangka kerja javascript yang popular, seperti Ember.js, Angular.js atau KnockoutJS, mempromosikan pengikatan data dua hala sebagai salah satu ciri utamanya. Ini tidak bermakna melaksanakannya dari awal adalah sukar, dan juga tidak bermakna menggunakan rangka kerja ini adalah satu-satunya pilihan kami apabila kami memerlukan fungsi ini. Idea asas di dalamnya sebenarnya agak asas, dan pelaksanaannya boleh diringkaskan dalam tiga perkara berikut:
Walaupun terdapat banyak cara untuk mencapai mata ini, cara yang mudah dan cekap ialah kami melaksanakannya melalui corak penerbit-pelanggan. Kaedahnya mudah: kita boleh menggunakan atribut data tersuai sebagai atribut yang perlu diikat dalam kod HTML. Semua objek JavaScript dan elemen DOM yang diikat bersama akan melanggan objek publish-subscribe ini. Pada bila-bila masa kami mengesan perubahan sama ada dalam objek Javascript atau elemen input HTML, kami menghantar proksi acara kepada objek publish-subscribe, dan kemudian lulus dan menyiarkan semua perubahan yang berlaku dalam objek dan elemen terikat melaluinya.
Contoh mudah dilaksanakan dengan jQuery
Agak mudah dan mudah untuk melaksanakan perkara yang kami bincangkan di atas melalui jQuery, kerana sebagai perpustakaan yang popular, ia membolehkan kami melanggan dan menerbitkan acara DOM dengan mudah, dan kami juga boleh menyesuaikan satu:
function DataBinder(object_id){ // Use a jQuery object as simple PubSub var pubSub=jQuery({}); // We expect a `data` element specifying the binding // in the form:data-bind-<object_id>="<property_name>" var data_attr="bind-"+object_id, message=object_id+":change"; // Listen to chagne events on elements with data-binding attribute and proxy // then to the PubSub, so that the change is "broadcasted" to all connected objects jQuery(document).on("change","[data-]"+data_attr+"]",function(eve){ var $input=jQuery(this); pubSub.trigger(message,[$input.data(data_attr),$input.val()]); }); // PubSub propagates chagnes to all bound elemetns,setting value of // input tags or HTML content of other tags pubSub.on(message,function(evt,prop_name,new_val){ jQuery("[data-"+data_attr+"="+prop_name+"]").each(function(){ var $bound=jQuery(this); if($bound.is("")){ $bound.val(new_val); }else{ $bound.html(new_val); } }); }); return pubSub; }
Bagi objek JavaScript, berikut ialah contoh pelaksanaan model data pengguna yang minimum:
function User(uid){ var binder=new DataBinder(uid), user={ attributes:{}, // The attribute setter publish changes using the DataBinder PubSub set:function(attr_name,val){ this.attributes[attr_name]=val; binder.trigger(uid+":change",[attr_name,val,this]); }, get:function(attr_name){ return this.attributes[attr_name]; }, _binder:binder }; // Subscribe to PubSub binder.on(uid+":change",function(evt,attr_name,new_val,initiator){ if(initiator!==user){ user.set(attr_name,new_val); } }); return user; }
Sekarang, apabila kami ingin mengikat sifat objek pada UI, kami hanya menetapkan atribut data yang sesuai pada elemen HTML yang sepadan.
// javascript var user=new User(123); user.set("name","Wolfgang"); // html <input type="number" data-bind-123="name" />
Perubahan nilai dalam kotak input secara automatik akan dipetakan kepada atribut nama pengguna, dan begitu juga sebaliknya. Anda sudah selesai!
Pelaksanaan yang tidak memerlukan jQuery
Kebanyakan projek pada masa kini biasanya menggunakan jQuery, jadi contoh di atas boleh diterima sepenuhnya. Tetapi bagaimana jika kita perlu bebas sepenuhnya daripada jQuery? Sebenarnya, ia tidak sukar untuk dilakukan (terutama apabila kami hanya menyediakan sokongan untuk IE8 dan ke atas). Akhir sekali, kita hanya perlu memerhati peristiwa DOM melalui corak penerbit-pelanggan.
function DataBinder( object_id ) { // Create a simple PubSub object var pubSub = { callbacks: {}, on: function( msg, callback ) { this.callbacks[ msg ] = this.callbacks[ msg ] || []; this.callbacks[ msg ].push( callback ); }, publish: function( msg ) { this.callbacks[ msg ] = this.callbacks[ msg ] || [] for ( var i = 0, len = this.callbacks[ msg ].length; i < len; i++ ) { this.callbacks[ msg ][ i ].apply( this, arguments ); } } }, data_attr = "data-bind-" + object_id, message = object_id + ":change", changeHandler = function( evt ) { var target = evt.target || evt.srcElement, // IE8 compatibility prop_name = target.getAttribute( data_attr ); if ( prop_name && prop_name !== "" ) { pubSub.publish( message, prop_name, target.value ); } }; // Listen to change events and proxy to PubSub if ( document.addEventListener ) { document.addEventListener( "change", changeHandler, false ); } else { // IE8 uses attachEvent instead of addEventListener document.attachEvent( "onchange", changeHandler ); } // PubSub propagates changes to all bound elements pubSub.on( message, function( evt, prop_name, new_val ) { var elements = document.querySelectorAll("[" + data_attr + "=" + prop_name + "]"), tag_name; for ( var i = 0, len = elements.length; i < len; i++ ) { tag_name = elements[ i ].tagName.toLowerCase(); if ( tag_name === "input" || tag_name === "textarea" || tag_name === "select" ) { elements[ i ].value = new_val; } else { elements[ i ].innerHTML = new_val; } } }); return pubSub; }
Model data boleh kekal tidak berubah, kecuali untuk panggilan kepada kaedah pencetus dalam jQuery dalam setter, yang boleh digantikan dengan kaedah penerbitan tersuai kami dalam PubSub.
// In the model's setter: function User( uid ) { // ... user = { // ... set: function( attr_name, val ) { this.attributes[ attr_name ] = val; // Use the `publish` method binder.publish( uid + ":change", attr_name, val, this ); } } // ... }
Kami menjelaskannya melalui contoh, dan sekali lagi mencapai hasil yang kami inginkan dengan kurang daripada seratus baris JavaScript tulen yang boleh diselenggara Kami berharap ia akan membantu semua orang dalam merealisasikan pengikatan dua hala data JavaScript.