js項目中雙向數(shù)據(jù)綁定的簡單實現(xiàn)方法
前言
雙向數(shù)據(jù)綁定 指的是當(dāng)對象的屬性發(fā)生變化時能夠同時改變對應(yīng)的UI,反之亦然。換句話說,如果我們有一個user對象,這個對象有一個name屬性,無論何時你對user.name設(shè)置了一個新值,UI也會展示這個新的值。同樣的,如果UI包含一個用于數(shù)據(jù)用戶名字的輸入框,輸入一個新值也會導(dǎo)致user對象的name屬性發(fā)生相應(yīng)的改變。
許多流行的javascript框架,像Ember.js,Angular.js或者KnockoutJS都會把雙向數(shù)據(jù)綁定作為其中的主要特性來宣傳。這并不意味著從頭開始實現(xiàn)它很難,也不意味著當(dāng)我們需要這種功能的時候,使用這些框架是我們唯一的選擇。內(nèi)部的潛在思想事實上是相當(dāng)基礎(chǔ)的,實現(xiàn)它可以歸納為以下三點:
- 我們需要一種方式確定哪個UI元素綁定在哪個屬性上。
- 我們需要監(jiān)控屬性和UI的變化
- 我們需要把所有綁定的對象和UI元素的變化傳播出去。
發(fā)布訂閱者模式
發(fā)布-訂閱模式其實是一種對象間一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)送改變時,所有依賴于它的對象都將得到狀態(tài)改變的通知。
訂閱者(Subscriber)把自己想訂閱的事件注冊(Subscribe)到調(diào)度中心(Event Channel),當(dāng)發(fā)布者(Publisher)發(fā)布該事件(Publish Event)到調(diào)度中心,也就是該事件觸發(fā)時,由調(diào)度中心統(tǒng)一調(diào)度(Fire Event)訂閱者注冊到調(diào)度中心的處理代碼。
結(jié)果

調(diào)用
html 調(diào)用 端 綁定 data-bind-phone="name"
<ul> <li class="block-phone fix bd-bottom"> <label for="J_verificationPhone" data-bind-phone="tishi"><span>手機號</span></label> <input class="fix1" id="J_verificationPhone" data-bind-phone="name" name="phone" type="text" /> <button class="right J_clickTime" type="button"> <span class="award-messages-btn2 J_messagesBtn1">獲取驗證碼</span> <span class="award-messages-btn2 J_messagesBtn2 none"><i>60</i>s后重發(fā)</span> </button> </li> <li class="block-verification fix"> <label for="J_verificationCode"><span>驗證碼</span></label> <input class="fix1" data-bind-code="tishi" id="J_verificationCode" data-bind-phone="name" name="verification-code" class="" type="" /> </li> </ul>
js 調(diào)用 看下面代碼注釋
/**
* function verficationCallback 回調(diào)方法
* [$btn1 description]
* data-bind-phone="name"
* @ message {[type]} 發(fā)生變化的字段phone
* @ prop_name {[type]} 字段的value name
* @ target {[type]} 目標(biāo)jsdom對象;
* @ targetValue {[type]} 目標(biāo)jsdom對象的value
*/// 監(jiān)聽回調(diào)函數(shù),函數(shù)會拿到targetvalue 的值, target js dom對象,便于對變化的字段進行操作?。?!
var User= require('../../entry/module/twoWayAudio.js');
var phone = new User('phone',verficationCallback);
function verficationCallback(message,prop_name,target,targetValue){
}
引入的源代碼 twoWayAudio
function DataBinder(object_id,verficationCallback){
// 創(chuàng)建一個簡單的pubSub對象
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,
message = object_id + ":change",
changeHandler = function(event) {
var target = event.target || event.srcElement, // IE8兼容
prop_name = target.getAttribute(data_attr);
if (prop_name && prop_name !== "") {
if(verficationCallback){
var targetValue = target.value;
verficationCallback (message,prop_name,target,targetValue);
}
pubSub.publish(message,prop_name,target.value);
}
};
// 監(jiān)聽事件變化,并代理到pubSub
if (document.addEventListener) {
document.addEventListener("keyup",changeHandler,false);
} else{
// IE8使用attachEvent而不是addEventListenter
document.attachEvent("onkeyup",changeHandler);
};
// pubSub將變化傳播到所有綁定元素
pubSub.on(message,function(event,prop_name,new_val){
var elements = document.querySelectorAll("[" + data_attr + "=" +prop_name + "]"),
tag_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;
}
function User(uid,verficationCallback) {
var binder = new DataBinder(uid,verficationCallback),
user = {
attribute : {},
// 屬性設(shè)置器使用數(shù)據(jù)綁定器pubSub來發(fā)布
set : function(attr_name,val) {
this.attribute[attr_name] = val;
binder.publish(uid + ":change",attr_name,val,this);
},
get : function(attr_name) {
return this.attribute[attr_name];
},
_binder : binder
};
binder.on(uid + ":change",function(event,attr_name,new_val,initiator) {
if (initiator !== user) {
user.set(attr_name,new_val);
}
});
return user;
}
module.exports = User;
// phone.set( "name", "lwl" );
// phone.set( "tishi", "提示" );
替代解決方案
上面只是在掩飾雙向數(shù)據(jù)綁定,其實這種需求可以更簡單的實現(xiàn) 嘿嘿
$('.block-phone #phone')[0].oninput=function(){
console.log($(this))
}
總結(jié)
到此這篇關(guān)于js項目中雙向數(shù)據(jù)綁定的簡單實現(xiàn)方法的文章就介紹到這了,更多相關(guān)js雙向數(shù)據(jù)綁定實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Javascript & DHTML DOM基礎(chǔ)和基本API
DOM是文檔對象模型(Document Object Model,是基于瀏覽器編程(在本教程中,可以說就是DHTML編程)的一套API接口,W3C出臺的推薦標(biāo)準(zhǔn),每個瀏覽器都有一些細微的差別,其中以Mozilla的瀏覽器最與標(biāo)準(zhǔn)接近。2008-07-07
javaScript Array(數(shù)組)相關(guān)方法簡述
javaScript Array(數(shù)組)相關(guān)方法簡述,讓大家更快的熟悉array數(shù)組的用法。2009-07-07
java和javascript獲取word文檔的書簽位置對比
這篇文章主要介紹了java和javascript獲取word文檔的書簽位置代碼對比,需要的朋友可以參考下2014-06-06
TypeScript使用vscode監(jiān)視代碼編譯的過程
這篇文章主要介紹了TypeScript使用vscode監(jiān)視代碼編譯,使用tsc 文件名稱可以將ts文件轉(zhuǎn)化為js文件,js文件可以引入在html文件中直接使用,需要的朋友可以參考下2021-12-12

