数据绑定——观察者模式
AngularJs是一款优秀的前端JS框架,它实现了将数据模型(data-model)关联到视图(UI)上。但个人认为正是由于它规范性的结构和体系导致使用的时候并不是很灵活。那么如何自己实现一个数据绑定视图的功能呢。
设想一下这样的应用场景,当我们修改数据或从服务器接收数据更新现有数据时,如何自动通知所有与数据关联的视图更新显示呢?观察者模式为这种场景提供了很好的解决方案。
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
每个HTML Dom都可以看成一个观察者,他们依赖数据对象,类图如图:
其中Observer类中doms为观察者的标签们,这里一个观察者包含多个标签,避免创建过多的观察者。Subject类作为数据对象的封装,由于javascript没有符号重载的功能,我们设计Setter和Getter的两个方法S()和G()。具体代码如下:
varObserver=Class.extend({doms:[],subject:null,ctor:function(_tag,_subject){this.doms=document.querySelectorAll(_tag);this.subject=_subject;this.subject.attach(this);},update:function(){for(vari=0;i<this.doms.length;i++){vartagName=this.doms[i].nodeName.toLowerCase();if(this.doms[i].getAttribute('bind-data')!=undefined){varbind=this.doms[i].getAttribute('bind-data');if(tagName=='input'||tagName=='select'){if(typeof(this.subject.G())=="object"&&Object.prototype.toString.call(this.subject.G()).toLowerCase()=="[objectobject]"&&!this.subject.G().length){this.doms[i].value=eval("this.subject.G()."+bind);}else{this.doms[i].value=this.subject.G();}}else{if(typeof(this.subject.G())=="object"&&Object.prototype.toString.call(this.subject.G()).toLowerCase()=="[objectobject]"&&!this.subject.G().length){this.doms[i].innerText=eval("this.subject.G()."+bind);}else{this.doms[i].innerText=this.subject.G();}}}}}});varSubject=Class.extend({observers:[],data:null,ctor:function(_data){this.data=_data;},attach:function(_observer){this.observers.push(_observer);_observer.update();},S:function(expre){if(typeof(expre)=='string'){if(expre.indexOf('=')==-1){this.data=expre;}else{if(typeof(this.data)=="object"&&Object.prototype.toString.call(this.data).toLowerCase()=="[objectobject]"&&!this.data.length){eval('this.data.'+expre);}else{this.data={};eval('this.data.'+expre);}}}else{this.data=expre;}this.notifyAllObservers();},G:function(){returnthis.data;},notifyAllObservers(){for(vari=0;i<this.observers.length;i++){this.observers[i].update();}}});
前端使用的代码如下:
<body>用户名:<inputvar='user'bind-data='username'id="username"/>密码:<inputvar="user"bind-data='password'id="username"/><p>用户名:<spanid="username"bind-data="username"></span></p><buttononclick="changeUserName()">修改用户名为jack</button><p>{username:'hello',password:'world'}</p><buttononclick="changeAll()">修改数据为上述值</button><p>将数据赋值为非JSON对象值</p><buttononclick="changeSingleV()">修改为非对象值</button></body><script>varuser=newSubject({username:'janwool',password:123456});varobserver_input=newObserver("[var='user']",user);varobserver_span=newObserver("#username",user);functionchangeUserName(){user.S("username='jack'");}functionchangeAll(){user.S({username:'hello',password:'world'});}functionchangeSingleV(){user.S('janwool');}</script>
效果如图:
根据结果,我们可以清楚的发现观察者的优势,数据的更新前端开发人员无需再操作Dom就可以更新视图,实现了数据实时更新。当然缺点也显而易见,那就是观察者过多时会数据的更新会过慢。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。