This is the 29th day of my participation in the August Wenwen Challenge.More challenges in August

preface

Two-way data binding refers to the ability to change the UI when an object’s properties change, and vice versa. In other words, if we have a User object that has a name attribute, whenever you set a new value to user.name, the UI will also display that new value. Similarly, if the UI contains an input field for data user names, entering a new value will cause the name property of the User object to change accordingly.

Many popular javascript frameworks like ember.js, angular. js, or KnockoutJS advertise two-way data binding as their main feature. That doesn’t mean it’s hard to implement from scratch, or that using these frameworks is our only option when we need this functionality. The underlying idea inside is actually quite basic, and its implementation can be summarized as follows:

  • We need a way to determine which UI elements are bound to which attributes.
  • We need to monitor property and UI changes
  • We need to propagate changes to all bound objects and UI elements.

Publish the subscriber model

The publish-subscribe model is a one-to-many dependency between objects. When the state of an object changes, all dependent objects are notified of the state change. Subscriber registers the Event they want to Subscribe to the Event Channel. When Publisher publishes the Event to the Event Channel, that is, when the Event is triggered, The processing code registered with the dispatch center by the Fire Event subscriber.

The results of

call

HTML calling end binding data-bind-phone=”name”

<ul> <li class="block-phone fix bd-bottom"> <label for="J_verificationPhone" Data-bind-phone ="tishi"><span> phone number </span></label> <input class="fix1" id="J_verificationPhone" data-bind-phone="name" name="phone" type="text" /> <button class="right J_clickTime" type="button"> <span class="award-messages-btn2 </span> <span class="award-messages-btn2 J_messagesBtn2 none">< I >60</ span> </button> </li> <li class="block-verification fix"> <label for="J_verificationCode">< SPAN ></ span></label> <input class="fix1" data-bind-code="tishi" id="J_verificationCode" data-bind-phone="name" name="verification-code" class="" type="" /> </li>  </ul>Copy the code

See the code comment below

/ * *

* function verficationCallback Callback method

 * [$btn1 description]

 * data-bind-phone=”name”

* @message {[type]} Changed field phone

* @prop_name {[type]} field value name

* @target {[type]} Target jsDOM object;

* @targetValue {[type]} The value of the target JsDOM object

*/// listen to the callback function, the function will get the targetValue, target JS DOM object, easy to operate on the changed field!!

var User= require('.. /.. /entry/module/twoWayAudio.js'); var phone = new User('phone',verficationCallback); function verficationCallback(message,prop_name,target,targetValue){ }Copy the code

Introduced source code twoWayAudio

Function DataBinder(object_id,verficationCallback){// 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(event) { var target = event.target || event.srcElement, // IE8 compatible prop_name = target.getAttribute(data_attr); if (prop_name && prop_name ! == "") { if(verficationCallback){ var targetValue = target.value; verficationCallback (message,prop_name,target,targetValue); } pubSub.publish(message,prop_name,target.value); }}; / / listen for an event, and the agent to the pubSub if (document. AddEventListener) {document. AddEventListener (" keyup ", changeHandler, false); } else{// IE8 uses attachEvent instead of addEventListenter document.attachEvent(" onKeyUp ",changeHandler); }; / / pubSub will spread to all the binding element pubSub change on (the message, the function (event, 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; } function User(uid,verficationCallback) { var binder = new DataBinder(uid,verficationCallback), user = { attribute : Set: function(attr_name,val) {this.attribute[attr_name] = val; binder.publish(uid + ":change",attr_name,val,this); }, get : function(attr_name) { return this.attribute[attr_name]; }, _binder : binder }; binder.on(uid + ":change",function(event,attr_name,new_val,initiator) { if (initiator ! == user) { user.set(attr_name,new_val); }}); return user; } module.exports = User; // phone.set( "name", "lwl" ); // phone. Set ("tishi", "prompt");Copy the code
Alternative solutions

The above is just covering up two-way data binding, but this requirement can be implemented much more easily


 $('.block-phone #phone')[0].oninput=function(){

 console.log($(this))

}

Copy the code