JavaScript中双向数据绑定详解

双向数据绑定指的是将对象属性变化绑定到UI,或者反之。换句话说,如果我们有一个拥有name属性的user对象,当我们给user.name赋予一个新值是UI也会相应的显示新的名字。同样的,如果UI包括了一个输入字段用来输入用户名,输入一个新的值会导致user对象中的那么属性发生变化。

许多流行的客户端JavaScript框架例如Ember.js,AngularJS以及KnockoutJS都将双向数据绑定作为自己的头号特性。但是这并不意味着从零开始实现双向数据绑定就很困难,同样的当我们需要双向数据绑定时并不是只能够选择这些框架其中的一个。双向数据绑定底层的思想非常的基本,它可以被压缩成为三个步骤:

1.我们需要一个方法来识别哪个UI元素被绑定了相应的属性

2.我们需要监视属性和UI元素的变化

3.我们需要将所有变化传播到绑定的对象和元素

虽然实现的方法有很多,但是最简单也是最有效的途径是使用发布者-订阅者模式。思想很简单:我们可以使用自定义的data属性在HTML代码中指明绑定。所有绑定起来的JavaScript对象以及DOM元素都将“订阅”一个发布者对象。任何时候如果JavaScript对象或者一个HTML输入字段被侦测到发生了变化,我们将代理事件到发布者-订阅者模式,这会反过来将变化广播并传播到所有绑定的对象和元素。

使用jQuery的简单实现

使用jQuery来实现双向数据绑定非常的直接且简单,因为这个流行的库能够是我们轻松的订阅和发布DOM事件,以及我们自定义的事件:

function DataBinder(object_id){
 //使用一个jQuery对象作为简单的订阅者发布者
 var pubSub = jQuery({});

 //我们希望一个data元素可以在表单中指明绑定:data-bind-<object_id>="<property_name>"  

 var data_attr = "bind-" + object_id,
   message = object_id + ":change";

 //使用data-binding属性和代理来监听那个元素上的变化事件
 // 以便变化能够“广播”到所有的关联对象 

 jQuery(document).on("change","[data-" + data_attr + "]",function(evt){
  var input = jQuery(this);
  pubSub.trigger(message, [ $input.data(data_attr),$input.val()]);
 });

 //PubSub将变化传播到所有的绑定元素,设置input标签的值或者其他标签的HTML内容 

 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;
}

在这个实验中可以按照以下代码简单的实现一个User模型:

function User(uid){
 var binder = new DataBinder(uid),

  user = {
   atttibutes: {},

   //属性设置器使用数据绑定器PubSub来发布变化 

   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);
   }
  })
}

现在,无论我们什么时候想把模型的属性绑定到UI的一部分上,我们只需要在相应的HTML元素上设置一个合适的data属性即可。

//JavaScript

var user = new User(123);
user.set("name","Wolfgang");

//html

<input type="number" data-bind-123="name" />

input字段的值会自动反映出user对象的name属性,反之亦然。任务完成了!

不使用jQuery来创建数据双向绑定

在入如今的大多数项目中,都可能已经用到了jQuery,因此完全可以借用前面的例子。但是如果我们更进一步,移除对jQuery的依赖会怎样呢?事实上,这并不是太困难(尤其是当我们限定只支持IE8以上的版本)。最终,我们需要使用原生的JavaScript来实现一个自定义的PubSub以及观察DOM事件。

function DataBinder(object_id){
 //创建一个简单地PubSub对象 

 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);
   }
 };

 //监听变化事件并代理到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;
}

模型可以和勤勉你的例子保持一直,除了在设置器中调用那个jQuery的trigger方法之外,它需要通过调用一个自定义的PubSub的publish方法来实现:

//在model的设置器中 

function User(uid){
//...

user = {
//...
set: function(attr_name,val){
 this.attribute[attr_name] = val;
 //使用“publish”方法
 binder.publish(uid+ ":change", attr_name, val,this);
  }
 }

 //...
}

再一次,我们使用原生的JavaScript代码实现了相同的结果,而不是使用臃肿的JavaScript框架。

本文译自easy two way data-binding in JavaScript,原文地址http://www.lucaongaro.eu/blog/2012/12/02/easy-two-way-data-binding-in-javascript/

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • jsp中将后台传递过来的json格式的list数据绑定到下拉菜单select

    复制代码 代码如下: <span style="white-space:pre"> </span><select><c:forEach var="fileList" items="${fileList}" varStatus="i"> <option value="${i.count}">${fileList.filePath}</optio

  • 实现非常简单的js双向数据绑定

    双向数据绑定指的就是,绑定对象属性的改变到用户界面的变化的能力,反之亦然.换种说法,如果我们有一个user对象和一个name属性,一旦我们赋了一个新值给user.name,在UI上就会显示新的姓名了.同样地,如果UI包含了一个输入用户姓名的输入框,输入一个新值就应该会使user对象的name属性做出相应的改变. 很多热门的JS框架客户端如Ember.js,Angular.js 或者KnockoutJS ,都在最新特性上刊登了双向数据绑定.这并不意味着从零实现它很难,也不是说需要这些功能的时候,采

  • AngularJS实践之使用NgModelController进行数据绑定

    前言 在Angular应用中,ng-model指令时不可缺少的一个部分,它用来将视图绑定到数据,是双向绑定魔法中重要的一环.ngModelController则是ng-model指令中所定义的controller.这个controller包含了一些用于数据绑定,验证,CSS更新,以及数值格式化和解析的服务.它不用来进行DOM渲染或者监听DOM事件.与DOM相关的逻辑都应该包含在其他的指令中,然后让这些指令来试用ngModelController中的数据绑定功能. 注意:本篇文章不是对NgMode

  • 详解JavaScript的AngularJS框架中的作用域与数据绑定

    AngularJS 简介 AngularJS 是由 Google 发起的一款开源的前端 MVC 脚本框架,既适合做普通 WEB 应用也可以做 SPA(单页面应用,所有的用户操作都在一个页面中完成).与同为 MVC 框架的 Dojo 的定位不同,AngularJS 在功能上更加轻量,而相比于 jQuery,AngularJS 又帮您省去了许多机械的绑定工作.在一些对开发速度要求高,功能模块不需要太丰富的非企业级 WEB 应用上,AngularJS 是一个非常好的选择.AngularJS 最为复杂同

  • angularjs学习笔记之双向数据绑定

    这次我们来详细讲解angular的双向数据绑定. 一.简单的例子 这个例子我们在第一节已经展示过了,要看的移步这里 这里实现的效果就是,在输入框输入内容,下面也会相应的改变对应的内容.这就实现了数据双向绑定. 二.取值表达式与ng-bind的使用 我们再看一个例子,点击这里,文中出现的第一个例子中,{{greeting.text}}和{{text}}就是一个取值表达式了,但是如果你一直刷新页面,你会发现这样一个问题,那就是页面有时候会一瞬间的出现"{{greeting.text}} {{text

  • AngularJS入门教程之数据绑定原理详解

    本文实例讲述了AngularJS数据绑定原理.分享给大家供大家参考,具体如下: 注 这篇文章主要是写给新手的,是给那些刚刚开始接触Angular,并且想了解数据帮定是如何工作的人.如果你已经对Angular比较了解了,那强烈建议你直接去阅读源代码. Angular用户都想知道数据绑定是怎么实现的.你可能会看到各种各样的词汇:$watch,$apply,$digest,dirty-checking...它们是什么?它们是如何工作的呢?这里我想回答这些问题,其实它们在官方的文档里都已经回答了,但是我

  • json数据处理及数据绑定

    一.json数据处理 1.json数据 {"img":"quizvault_internet_test_banner@2x.png", "golds":"200", "praise":"64000", "tit":"互联网给工作带来的麻烦", "tit_describe":"在朋友圈转发身体被掏空,HR找你深情谈话:不

  • JavaScript实现LI列表数据绑定的方法

    本文实例讲述了JavaScript实现LI列表数据绑定的方法.分享给大家供大家参考.具体如下: 利用JavaScript进行LI列表数据绑定,获取列表里面对应的LI,这是一位高人写的代码,看了才知道,原来并不很复杂,为什么之前用的方法那么笨? 运行效果如下图所示: 具体代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/

  • AngularJS 双向数据绑定详解简单实例

    angular的双向数据绑定,个人理解是,通过model建立数据模型,那么视图上的数据就会对应存储在angular程序里,视图上的数据变化会同步到model,model的数据改变也会同步到视图. 下面的demo演示: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>hello, AngularJS!</titl

  • JavaScript数据绑定实现一个简单的 MVVM 库

    推荐阅读: 实现非常简单的js双向数据绑定 MVVM 是 Web 前端一种非常流行的开发模式,利用 MVVM 可以使我们的代码更专注于处理业务逻辑而不是去关心 DOM 操作.目前著名的 MVVM 框架有 vue, avalon , react 等,这些框架各有千秋,但是实现的思想大致上是相同的:数据绑定 + 视图刷新.出于好奇和一颗愿意折腾的心,我自己也沿着这个方向写了一个最简单的 MVVM 库 ( mvvm.js ),总共 2000 多行代码,指令的命名和用法与 vue 相似,在这里分享一下实

随机推荐