js項目中雙向數據綁定的簡單實現方法

前言

雙向數據綁定 指的是當對象的屬性發生變化時能夠同時改變對應的UI,反之亦然。換句話說,如果我們有一個user對象,這個對象有一個name屬性,無論何時你對user.name設置瞭一個新值,UI也會展示這個新的值。同樣的,如果UI包含一個用於數據用戶名字的輸入框,輸入一個新值也會導致user對象的name屬性發生相應的改變。

許多流行的javascript框架,像Ember.js,Angular.js或者KnockoutJS都會把雙向數據綁定作為其中的主要特性來宣傳。這並不意味著從頭開始實現它很難,也不意味著當我們需要這種功能的時候,使用這些框架是我們唯一的選擇。內部的潛在思想事實上是相當基礎的,實現它可以歸納為以下三點:

  • 我們需要一種方式確定哪個UI元素綁定在哪個屬性上。
  • 我們需要監控屬性和UI的變化
  • 我們需要把所有綁定的對象和UI元素的變化傳播出去。

發佈訂閱者模式

發佈-訂閱模式其實是一種對象間一對多的依賴關系,當一個對象的狀態發送改變時,所有依賴於它的對象都將得到狀態改變的通知。

訂閱者(Subscriber)把自己想訂閱的事件註冊(Subscribe)到調度中心(Event Channel),當發佈者(Publisher)發佈該事件(Publish Event)到調度中心,也就是該事件觸發時,由調度中心統一調度(Fire Event)訂閱者註冊到調度中心的處理代碼。

結果

調用

html  調用 端 綁定 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後重發</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 調用 看下面代碼註釋

/**
 * function verficationCallback 回調方法
 * [$btn1 description]
 * data-bind-phone="name"
 * @ message {[type]}   發生變化的字段phone
 * @ prop_name {[type]}  字段的value  name
 * @ target {[type]}      目標jsdom對象;
 * @ targetValue {[type]}  目標jsdom對象的value
 */// 監聽回調函數,函數會拿到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){  
// 創建一個簡單的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);
}
};

// 監聽事件變化,並代理到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 : {},
  // 屬性設置器使用數據綁定器pubSub來發佈
  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", "提示" );  

替代解決方案

上面隻是在掩飾雙向數據綁定,其實這種需求可以更簡單的實現 嘿嘿

 $('.block-phone #phone')[0].oninput=function(){
 console.log($(this))
}

總結

到此這篇關於js項目中雙向數據綁定的簡單實現方法的文章就介紹到這瞭,更多相關js雙向數據綁定實現內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: