JavaScript中雙向數(shù)據(jù)綁定詳解
雙向數(shù)據(jù)綁定指的是將對(duì)象屬性變化綁定到UI,或者反之。換句話說(shuō),如果我們有一個(gè)擁有name屬性的user對(duì)象,當(dāng)我們給user.name賦予一個(gè)新值是UI也會(huì)相應(yīng)的顯示新的名字。同樣的,如果UI包括了一個(gè)輸入字段用來(lái)輸入用戶(hù)名,輸入一個(gè)新的值會(huì)導(dǎo)致user對(duì)象中的那么屬性發(fā)生變化。
許多流行的客戶(hù)端JavaScript框架例如Ember.js,AngularJS以及KnockoutJS都將雙向數(shù)據(jù)綁定作為自己的頭號(hào)特性。但是這并不意味著從零開(kāi)始實(shí)現(xiàn)雙向數(shù)據(jù)綁定就很困難,同樣的當(dāng)我們需要雙向數(shù)據(jù)綁定時(shí)并不是只能夠選擇這些框架其中的一個(gè)。雙向數(shù)據(jù)綁定底層的思想非常的基本,它可以被壓縮成為三個(gè)步驟:
1.我們需要一個(gè)方法來(lái)識(shí)別哪個(gè)UI元素被綁定了相應(yīng)的屬性
2.我們需要監(jiān)視屬性和UI元素的變化
3.我們需要將所有變化傳播到綁定的對(duì)象和元素
雖然實(shí)現(xiàn)的方法有很多,但是最簡(jiǎn)單也是最有效的途徑是使用發(fā)布者-訂閱者模式。思想很簡(jiǎn)單:我們可以使用自定義的data屬性在HTML代碼中指明綁定。所有綁定起來(lái)的JavaScript對(duì)象以及DOM元素都將“訂閱”一個(gè)發(fā)布者對(duì)象。任何時(shí)候如果JavaScript對(duì)象或者一個(gè)HTML輸入字段被偵測(cè)到發(fā)生了變化,我們將代理事件到發(fā)布者-訂閱者模式,這會(huì)反過(guò)來(lái)將變化廣播并傳播到所有綁定的對(duì)象和元素。
使用jQuery的簡(jiǎn)單實(shí)現(xiàn)
使用jQuery來(lái)實(shí)現(xiàn)雙向數(shù)據(jù)綁定非常的直接且簡(jiǎn)單,因?yàn)檫@個(gè)流行的庫(kù)能夠是我們輕松的訂閱和發(fā)布DOM事件,以及我們自定義的事件:
function DataBinder(object_id){
//使用一個(gè)jQuery對(duì)象作為簡(jiǎn)單的訂閱者發(fā)布者
var pubSub = jQuery({});
//我們希望一個(gè)data元素可以在表單中指明綁定:data-bind-<object_id>="<property_name>"
var data_attr = "bind-" + object_id,
message = object_id + ":change";
//使用data-binding屬性和代理來(lái)監(jiān)聽(tīng)那個(gè)元素上的變化事件
// 以便變化能夠“廣播”到所有的關(guān)聯(lián)對(duì)象
jQuery(document).on("change","[data-" + data_attr + "]",function(evt){
var input = jQuery(this);
pubSub.trigger(message, [ $input.data(data_attr),$input.val()]);
});
//PubSub將變化傳播到所有的綁定元素,設(shè)置input標(biāo)簽的值或者其他標(biāo)簽的HTML內(nèi)容
pubSub.on(message,function(evt,prop_name,new_val){
jQuery("[data-" + data_attr + "=" + prop_name + "]").each(function(){
var $bound = jQuery(this);
if($bound.is("input,text area,select")){
$bound.val(new_val);
}else{
$bound.html(new_val);
}
});
});
return pubSub;
}
在這個(gè)實(shí)驗(yàn)中可以按照以下代碼簡(jiǎn)單的實(shí)現(xiàn)一個(gè)User模型:
function User(uid){
var binder = new DataBinder(uid),
user = {
atttibutes: {},
//屬性設(shè)置器使用數(shù)據(jù)綁定器PubSub來(lái)發(fā)布變化
set: function(attr_name,val){
this.attriures[attr_name] = val;
binder.trigger(uid + ":change", [attr_name, val, this]);
},
get: function(attr_name){
return this.attributes[attr_name];
},
_binder: binder
};
binder.on(uid +":change",function(vet,attr_name,new_val,initiator){
if(initiator !== user){
user.set(attr_name,new_val);
}
})
}
現(xiàn)在,無(wú)論我們什么時(shí)候想把模型的屬性綁定到UI的一部分上,我們只需要在相應(yīng)的HTML元素上設(shè)置一個(gè)合適的data屬性即可。
//JavaScript
var user = new User(123);
user.set("name","Wolfgang");
//html
<input type="number" data-bind-123="name" />
input字段的值會(huì)自動(dòng)反映出user對(duì)象的name屬性,反之亦然。任務(wù)完成了!
不使用jQuery來(lái)創(chuàng)建數(shù)據(jù)雙向綁定
在入如今的大多數(shù)項(xiàng)目中,都可能已經(jīng)用到了jQuery,因此完全可以借用前面的例子。但是如果我們更進(jìn)一步,移除對(duì)jQuery的依賴(lài)會(huì)怎樣呢?事實(shí)上,這并不是太困難(尤其是當(dāng)我們限定只支持IE8以上的版本)。最終,我們需要使用原生的JavaScript來(lái)實(shí)現(xiàn)一個(gè)自定義的PubSub以及觀察DOM事件。
function DataBinder(object_id){
//創(chuàng)建一個(gè)簡(jiǎn)單地PubSub對(duì)象
var pubSub = {
callbacks: {}.
on: function(msg,calssback){
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<lenli++){
this.callbacks[msg][i].apply(this,arguments);
}
}
},
data_attr = "data-bind-" + object_id,
message = object_id + ":change",
changeHandler = function(evt){
var target = evt.target || evt.srcElemnt, //IE8兼容
prop_name = target.getAttribute(data_attr);
if(prop_name && prop_name !== ""){
pubSub.publish(message,prop_name,target.value);
}
};
//監(jiān)聽(tīng)變化事件并代理到PubSub
if(document.addEventListener){
document.addEventListener("change",changeHandler,false);
}else{
//IE8使用attachEvent而不是addEventListener
document.attachEvent("onchange",changeHandler);
}
//PubSub將變化傳播到所有綁定元素
pubSub.on(message,function(vet,prop_name,new)_val){
var elements = document.querySelectorAll("[" + data_attr + "=" + prop_name + "]"),
tah_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;
}
模型可以和勤勉你的例子保持一直,除了在設(shè)置器中調(diào)用那個(gè)jQuery的trigger方法之外,它需要通過(guò)調(diào)用一個(gè)自定義的PubSub的publish方法來(lái)實(shí)現(xiàn):
//在model的設(shè)置器中
function User(uid){
//...
user = {
//...
set: function(attr_name,val){
this.attribute[attr_name] = val;
//使用“publish”方法
binder.publish(uid+ ":change", attr_name, val,this);
}
}
//...
}
再一次,我們使用原生的JavaScript代碼實(shí)現(xiàn)了相同的結(jié)果,而不是使用臃腫的JavaScript框架。
本文譯自easy two way data-binding in JavaScript,原文地址http://www.lucaongaro.eu/blog/2012/12/02/easy-two-way-data-binding-in-javascript/
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- vue.js數(shù)據(jù)綁定的方法(單向、雙向和一次性綁定)
- 實(shí)現(xiàn)非常簡(jiǎn)單的js雙向數(shù)據(jù)綁定
- javascript實(shí)現(xiàn)數(shù)據(jù)雙向綁定的三種方式小結(jié)
- 輕松實(shí)現(xiàn)javascript數(shù)據(jù)雙向綁定
- JS原生數(shù)據(jù)雙向綁定實(shí)現(xiàn)代碼
- JS數(shù)據(jù)雙向綁定原理與用法實(shí)例分析
- js實(shí)現(xiàn)視圖和數(shù)據(jù)雙向綁定的方法分析
- js項(xiàng)目中雙向數(shù)據(jù)綁定的簡(jiǎn)單實(shí)現(xiàn)方法
相關(guān)文章
微信小程序利用canvas 繪制幸運(yùn)大轉(zhuǎn)盤(pán)功能
本文通過(guò)一段簡(jiǎn)單的實(shí)例代碼給大家介紹微信小程序利用canvas 繪制幸運(yùn)大轉(zhuǎn)盤(pán),代碼很簡(jiǎn)單,感興趣的朋友跟隨腳本之家小編一起看看吧2018-07-07
ES6模板字符串和標(biāo)簽?zāi)0宓膽?yīng)用實(shí)例分析
這篇文章主要介紹了ES6模板字符串和標(biāo)簽?zāi)0宓膽?yīng)用,結(jié)合實(shí)例形式分析了ES6模板字符串和標(biāo)簽?zāi)0宓墓δ?、原理、用法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-06-06
JavaScript實(shí)現(xiàn)瀑布動(dòng)畫(huà)
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)瀑布動(dòng)畫(huà),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
js實(shí)現(xiàn)的仿新浪微博完美的時(shí)間組件升級(jí)版
本博客沒(méi)有華麗的布局,只求樸實(shí)的js的代碼,只為js代碼愛(ài)好者提供,一周大概會(huì)出1-2篇js前沿代碼的文章.只是代碼,不說(shuō)技術(shù)2011-12-12
js圖片滾動(dòng)效果時(shí)間可隨意設(shè)定當(dāng)鼠標(biāo)移上去時(shí)停止
這篇文章主要介紹了js圖片滾動(dòng)效果時(shí)間可隨意設(shè)定當(dāng)鼠標(biāo)移上去時(shí)停止,需要的朋友可以參考下2014-06-06
js判斷手機(jī)訪問(wèn)或者PC的幾個(gè)例子(常用于手機(jī)跳轉(zhuǎn))
js判斷手機(jī)或者PC的例子我們?cè)趲缀跛芯W(wǎng)站都會(huì)有這段代碼了,現(xiàn)在手機(jī)流量與pc差不多了,下面來(lái)看兩段js判斷手機(jī)或者PC例子吧2015-12-12
Javascript模仿淘寶信用評(píng)價(jià)實(shí)例(附源碼)
這篇文章主要介紹了Javascript模仿淘寶信用評(píng)價(jià)功能實(shí)現(xiàn)方法,以完整實(shí)例形式分析了JavaScript響應(yīng)鼠標(biāo)事件動(dòng)態(tài)改變頁(yè)面元素的相關(guān)技巧,并附帶了完整的實(shí)例代碼供讀者下載參考,需要的朋友可以參考下2015-11-11

