溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

數(shù)據(jù)綁定——觀察者模式

發(fā)布時間:2020-07-01 16:51:46 來源:網(wǎng)絡(luò) 閱讀:848 作者:janwool 欄目:開發(fā)技術(shù)

  AngularJs是一款優(yōu)秀的前端JS框架,它實現(xiàn)了數(shù)據(jù)模型(data-model)關(guān)聯(lián)到視圖(UI)上。但個人認(rèn)為正是由于它規(guī)范性的結(jié)構(gòu)和體系導(dǎo)致使用的時候并不是很靈活。那么如何自己實現(xiàn)一個數(shù)據(jù)綁定視圖的功能呢。

        設(shè)想一下這樣的應(yīng)用場景,當(dāng)我們修改數(shù)據(jù)或從服務(wù)器接收數(shù)據(jù)更新現(xiàn)有數(shù)據(jù)時,如何自動通知所有與數(shù)據(jù)關(guān)聯(lián)的視圖更新顯示呢?觀察者模式為這種場景提供了很好的解決方案。

        觀察者模式定義對象間的一種一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新。

        每個HTML Dom都可以看成一個觀察者,他們依賴數(shù)據(jù)對象,類圖如圖:

數(shù)據(jù)綁定——觀察者模式


        其中Observer類中doms為觀察者的標(biāo)簽們,這里一個觀察者包含多個標(biāo)簽,避免創(chuàng)建過多的觀察者。Subject類作為數(shù)據(jù)對象的封裝,由于javascript沒有符號重載的功能,我們設(shè)計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()">修改數(shù)據(jù)為上述值</button>
		<p>將數(shù)據(jù)賦值為非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>


效果如圖:

數(shù)據(jù)綁定——觀察者模式


根據(jù)結(jié)果,我們可以清楚的發(fā)現(xiàn)觀察者的優(yōu)勢,數(shù)據(jù)的更新前端開發(fā)人員無需再操作Dom就可以更新視圖,實現(xiàn)了數(shù)據(jù)實時更新。當(dāng)然缺點(diǎn)也顯而易見,那就是觀察者過多時會數(shù)據(jù)的更新會過慢。


附件:http://down.51cto.com/data/2368542
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI