服务热线:19998000864

站内公告:

双向数据绑定指的是当对象的属性发生变化时能够同时改变对应的UI,反之亦然。换句话说,如果我们有一个user对象,这个对象有一个name属性,无论何时你对user.name设置了一个新值,UI也会展示这个新的值。同样的,如果UI包含一个用于数据用户名字的输入框,输入一个新值也会导致user对象的name属性发生相应的改变。许多流行的可爱小鸟对对碰框架,像Ember.js,Angular.js或者KnockoutJS都会把双向数据绑定作为其中的主要特性来宣传。这并不意味着从头开
Java高级开发

当前位置:Java高级开发

可爱小鸟对对碰-轻松实现javascript数据双向绑定

时间:2021-09-19 

双向数据绑定指的是当对象的属性发生变化时能够同时改变对应的UI,反之亦然。换句话说,如果我们有一个user对象,这个对象有一个name属性,无论何时你对user.name设置了一个新值,UI也会展示这个新的值。同样的,如果UI包含一个用于数据用户名字的输入框,输入一个新值也会导致user对象的name属性发生相应的改变。

许多流行的可爱小鸟对对碰框架,像Ember.js,Angular.js或者KnockoutJS都会把双向数据绑定作为其中的主要特性来宣传。这并不意味着从头开始实现它很难,也不意味着当我们需要这种功能的时候,使用这些框架是我们唯一的选择。内部的潜在思想事实上是相当基础的,实现它可以归纳为以下三点:

我们需要一种方式确定哪个UI元素绑定在哪个属性上。

我们需要监控属性和UI的变化

我们需要把所有绑定的对象和UI元素的变化传播出去。

尽管有好多种方式去实现这几点,一种简单高效的方法是我们通过发布订阅者模式来实现。方法很简单:我们可以使用定制的data属性作为HTML代码中需要绑定的属性。所有的绑定在一起的Javascript对象和DOM元素将会订阅这个发布订阅对象。任何时候我们检测到无论是Javascript对象亦或是HTML的input元素的变化,我们都是把事件代理传递给发布订阅对象,然后通过它把所有发生在绑定的对象和元素的的变化传递和广播出去。

通过jQuery实现我们上面讨论的东西是相当简单明了的,因为作为一个流行的库,它让我们很简单的实现订阅和发布DOM事件,同时我们也可以定制一个:

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-="

" var data_attr="bind-"+object_id, mess**e=object_id+":change"; // Listen to ch**ne 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(mess**e,[$input.data(data_attr),$input.val()]); }); // PubSub prop**ates ch**nes to all bound elemetns,setting value of // input t**s or HTML content of other t**s pubSub.on(mess**e,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; }

至于可爱小鸟对对碰对象,下面是最小化的user数据模型实现的例子:

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; }

现在,无论何时我们想要绑定一个对象的属性到UI上,我们只要在对应的HTML元素上设置合适的data属性。

// 可爱小鸟对对碰 var user=new User(123); user.set("name","Wolfgang"); // html

input输入框上值得变化会自动的映射到user的name属性,反之亦然。大功告成!

现在的大部分项目一般jQuery都已经在使用啦,所以上面的例子是完全可以接受的。但是如果我们需要完全不依赖jQuery,那么该怎么实现呢?好吧,事实上其实也不难办到(特别是当我们把对IE的支持只提供IE8以上的支持)。最后,我们只是要通过发布订阅者模式来观察DOM事件而已。

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, mess**e = 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( mess**e, 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 prop**ates changes to all bound elements pubSub.on( mess**e, function( evt, prop_name, new_val ) { var elements = document.querySelectorAll("[" + data_attr + "=" + prop_name + "]"), t**_name; for ( var i = 0, len = elements.length; i < len; i++ ) { t**_name = elements[ i ].t**Name.toLowerCase(); if ( t**_name === "input" || t**_name === "textarea" || t**_name === "select" ) { elements[ i ].value = new_val; } else { elements[ i ].innerHTML = new_val; } } }); return pubSub; }

数据模型可以保持不变,除了在setter中对jQuery中trigger方法的调用,我们可以通过我们在PubSub中自定义的publish方法来代替。

// 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 ); } } // ... }

通过实例讲解,并又一次通过一百行不到,又可维护的纯可爱小鸟对对碰完成了我们想要的结果,希望对大家实现可爱小鸟对对碰数据双向绑定有所帮助。


首页 | 项目管理 | 前端开发 | 软件测试 | python | 新媒体短视频 | Android高级开发 | C/C++ | 产品经理 | 云计算大数据 |

19998000864

友情链接:

地址:电话:19998000864邮箱:PTJaOF@www.chhuada.com

微信扫一扫

微信扫一扫