AngularJs是一款優秀的前端JS框架,它實現了將數據模型(data-model)關聯到視圖(UI)上。但個人認為正是由于它規范性的結構和體系導致使用的時候并不是很靈活。那么如何自己實現一個數據綁定視圖的功能呢。
設想一下這樣的應用場景,當我們修改數據或從服務器接收數據更新現有數據時,如何自動通知所有與數據關聯的視圖更新顯示呢?觀察者模式為這種場景提供了很好的解決方案。
觀察者模式定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并被自動更新。
每個HTML Dom都可以看成一個觀察者,他們依賴數據對象,類圖如圖:

其中Observer類中doms為觀察者的標簽們,這里一個觀察者包含多個標簽,避免創建過多的觀察者。Subject類作為數據對象的封裝,由于javascript沒有符號重載的功能,我們設計Setter和Getter的兩個方法S()和G()。具體代碼如下:
var Observer = Class.extend({
doms:[],
subject:null,
ctor:function(_tag,_subject){
this.doms = document.querySelectorAll(_tag);
this.subject = _subject;
this.subject.attach(this);
},
update:function(){
for(var i = 0;i < this.doms.length;i++){
var tagName = this.doms[i].nodeName.toLowerCase();
if(this.doms[i].getAttribute('bind-data') != undefined){
var bind = 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() == "[object object]" && !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() == "[object object]" && !this.subject.G().length){
this.doms[i].innerText = eval("this.subject.G()." + bind);
}else{
this.doms[i].innerText = this.subject.G();
}
}
}
}
}
});
var Subject = 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() == "[object object]" && !this.data.length){
eval('this.data.' + expre);
}else{
this.data = {};
eval('this.data.' + expre);
}
}
}else{
this.data = expre;
}
this.notifyAllObservers();
},
G:function(){
return this.data;
},
notifyAllObservers(){
for(var i = 0;i < this.observers.length;i++){
this.observers[i].update();
}
}
});前端使用的代碼如下:
<body>
用戶名:<input var = 'user' bind-data = 'username' id = "username"/>
密碼:<input var = "user" bind-data = 'password' id = "username"/>
<p>用戶名:<span id = "username" bind-data="username"></span></p>
<button onclick = "changeUserName()">修改用戶名為jack</button>
<p>{username:'hello',password:'world'}</p>
<button onclick = "changeAll()">修改數據為上述值</button>
<p>將數據賦值為非JSON對象值</p>
<button onclick = "changeSingleV()">修改為非對象值</button>
</body>
<script>
var user = new Subject({username:'janwool',password:123456});
var observer_input = new Observer("[var='user']",user);
var observer_span = new Observer("#username",user);
function changeUserName(){
user.S("username='jack'");
}
function changeAll(){
user.S({username:'hello',password:'world'});
}
function changeSingleV(){
user.S('janwool');
}
</script>效果如圖:

根據結果,我們可以清楚的發現觀察者的優勢,數據的更新前端開發人員無需再操作Dom就可以更新視圖,實現了數據實時更新。當然缺點也顯而易見,那就是觀察者過多時會數據的更新會過慢。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。