js实现视图和数据双向绑定的方法分析

本文实例讲述了js实现视图和数据双向绑定的方法。分享给大家供大家参考,具体如下:

前言

视图和数据绑定,使视图和逻辑层分离,使视图层变为数据驱动是前端的一大进步。由此诞生了mvvm类的前端框架,大大提升了开发的效率。

那么在使用旧有的项目中,如何使用更加先进的设计模式来替换掉大量的面向过程编程。

各大框架对于数据绑定的实现都有各自的方式,这里不做深入只是简单介绍一下。

Vue使用了es5  Object.defineProperty的特性来实现对数据读取和设置的监听,是一种元编程的方式。个人感觉,比之angularJS的脏检查数据比对更新机制确实要科学一点。

Object.defineProperty实现了对数据get和set的重新编程,能让我们在做最简单的 = 赋值操作时来做一些事,具体的实现就不放在这了。这不是今天要讨论的重点。

在低版本浏览器中显然对于这点的支持也不够友好,那么我可以想一种替代性的方案来达到和Object.defineProperty所类似的效果。在微信小程序中设置数据需要使用set方法,因为小程序的视图层本质上是分离于js引擎的。这样等于手动告诉视图层某个数据更新了。那么我也可以使用这种方法来实现对数据更新的监听。

实现

首先我们需要一个对象来保存数据。并且在其数据变更时做一些事情。可以定义一个构造函数来获得这个对象。

因为get和set方法很显然是公共的,所以可以定义在原型对象上。

var $vm = function(obj) {
  this.data = obj.data
}
$vm.prototype.get = function(prop) {
  //返回当前值
  return this.data[prop]
}
$vm.prototype.set = function (prop, val) {
  //赋值操作
  this.data[prop] = val
}

如果这时候实例化一个这个构造函数的对象,这个对象上就会存在get和set方法,看代码可以知道他对这个对象上的data生效。

这样一个简单的get set方法就设置好了。一个是获取当前对象属性的值,一个是对其设置新的值。

如果在设置的时候我们再去触发相应的视图层的操作,那么一个简单的绑定就实现了。

var vm = new $vm({
  // 绑定的变量值
  data: {
    info: true
  }
})

取值

vm.get('info')

存值

vm.set('info', false)

如果我们在set方法里添加console.log()那么每次数据变动都会被打印出来。

使用set方法来替代=号的赋值操作可以一定意义上代替Object.defineProperty的效果。并且兼容性更好。

对视图数据进行绑定是一个很大的问题,怎样使数据的变动在视图上体现。

这里一个最简单的替代实现就是去手动绑定数据和视图。用jq的方式。

比如在set里面执行对应这个属性变动的回掉函数。

例如

$vm.prototype.set = function (prop, val) {
  this.data[prop] = val
  if (this.$$fn[prop]) {
    this.$$fn[prop](val, oldVal)
  }
}

可以看到如果当前对象上$$fn属性上如果存在同名的函数,会执行。

这样我们可以把绑定dom的操作来放到里面显示。

这种写法显然可能不太利于维护,于是我想可以参照vue框架的watch观察者来实现。

在vue中观察对象上某个值的改变可以do someThing。

所以在此可以借鉴。

// 存值
$vm.prototype.set = function (prop, val) {
    var oldVal = this.data[prop]
    this.data[prop] = val

    //如果发现被列入观察者 执行函数并注入修改后的值
    if (this.watch[prop]) {
      this.watch[prop](val, oldVal)
    }
}

鸽了,这里省略3000字。哈哈哈哈,因为写了好多代码但是没写博客,懒得写了直接跳过吧,有兴趣的童鞋直接看源码。虚拟dom和{{}}表达式,观察者模式,计算属性等等。

突发奇想,想要对数据层绑定还有个简单的方案。利用html data的自定义属性来绑定相应的属性,利用jq选择器来找到对应的节点进行更新。这也是一种替代的方案。

JQ选择器,选择属性=某值的dom节点。利用这个选择器可以来获得所有绑定了某属性的节点。

<div data-vm="info">
</div>
$('[data-vm="info"]').text(300)

这个节点的值变为了300。

所以利用自定义属性和jq的选择器,只要在dom节点上写上data-vm(取的名字)然后等于要绑定的值,那么就可以实现对视图的绑定了。

// 存值
$vm.prototype.set = function (prop, val) {
  try {
    var oldVal = this.data[prop]
    this.data[prop] = val
    //如果发现被列入观察者 执行函数并注入修改后的值
    if (this.watch[prop]) {
      this.watch[prop](val, oldVal)
    }
    //查询是否有订阅值
    if (this.$$fn[prop]) {
      this.$$fn[prop](val, oldVal)
    }
    //查询是否有依赖于此项的计算属性
    if (this.$$count[prop]) {
      // 获得所有依赖此值的计算属性
      var arr = this.$$count[prop]
      //循环遍历每个计算属性并重新计算它的值
      for (var i = 0; i < arr.length; i++) {
        var item = arr[i]
        // 获得返回的值
        this.data[item] = this.computed[item]()
      }
    }
    // 如果节点绑定了此属性 更新节点
    var dom = $('[data-vm="' + prop + '"]')
    if (dom) {
      dom.text(val)
    }
    // this.updateView()
  } catch(e) {
    console.log('error setData' + prop)
  }
}

实现成功!

目前绑定的各种方式我改了蛮多,具体的代码在github上,有兴趣的童鞋可以看一看。

项目github地址https://github.com/unjust-life/mvvm

更多关于JavaScript相关内容可查看本站专题:《JavaScript操作DOM技巧总结》、《JavaScript页面元素操作技巧总结》、《JavaScript事件相关操作与技巧大全》、《JavaScript查找算法技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript错误与调试技巧总结》

希望本文所述对大家JavaScript程序设计有所帮助。

(0)

相关推荐

  • Nuxt.js 数据双向绑定的实现

    假定我们有一个需求,一开始通过mounted()将一个字符串渲染在页面上,但是我们经过操作后修改了数据并且需要将得到的结果重新异步渲染到页面中去,而不是跳转刷新页面来重新渲染 首先模板中data()中定义数据,并且要将定义的数据显示出来 <template> <div> <span @click="click">{{ text }}</span> </div> </template> <script>

  • js最简单的双向绑定实例讲解

    把代码复制放到页面里面运行看一下效果就好了 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="text" id="myinput" > <sc

  • 详解Vue.js之视图和数据的双向绑定(v-model)

    1.使用v-model指令,使得视图和数据实现双向绑定.v-model主要用在表单的input输入框,完成视图和数据的双向绑定. 2.JavaScript代码 <script type="text/javascript" src="../js/vue-1.0.21.js"></script> <script type="text/javascript"> window.onload = function() {

  • Vue.js 踩坑记之双向绑定

    这篇体验一下VUE的双向绑定 <html> <head> <meta charset="utf-8"> </head> <body> <script src="https://unpkg.com/vue/dist/vue.min.js"></script> <div id="app"> <input type="text" v

  • 使用Object.defineProperty实现简单的js双向绑定

    缘起 前几天在看一些流行的迷你mvvm框架(比如avalon.js. vue.js 这种较轻的框架,而非Angularjs.Emberjs这种较重的框架)的实现.现代流行的mvvm框架一般都会将数据双向绑定(two-ways data binding)做掉,作为框架自身的一个卖点( Ember.js 貌似是不支持数据双向绑定的.),而且每种框架双向数据绑定的实现方式都不太一致,比如Anguarjs内部使用的是 脏检查 ,而avalon.js内部实现方式的本质是设置 属性访问器 . 这里不打算具体

  • Vue.js单向绑定和双向绑定实例分析

    本文实例讲述了Vue.js单向绑定和双向绑定.分享给大家供大家参考,具体如下: 1.单向绑定 单向数据绑定的实现思路: ① 所有数据只有一份 ② 一旦数据变化,就去更新页面(只有data-->DOM,没有DOM-->data) ③ 若用户在页面上做了更新,就手动收集(双向绑定是自动收集),合并到原有的数据中. <!DOCTYPE html> <html> <head></head> <body> <div id="ap

  • 轻松实现javascript数据双向绑定

    双向数据绑定指的是当对象的属性发生变化时能够同时改变对应的UI,反之亦然.换句话说,如果我们有一个user对象,这个对象有一个name属性,无论何时你对user.name设置了一个新值,UI也会展示这个新的值.同样的,如果UI包含一个用于数据用户名字的输入框,输入一个新值也会导致user对象的name属性发生相应的改变. 许多流行的javascript框架,像Ember.js,Angular.js或者KnockoutJS都会把双向数据绑定作为其中的主要特性来宣传.这并不意味着从头开始实现它很难,

  • jquery,js简单实现类似Angular.js双向绑定

    刚了解了下Angular.js,发现Angular.js绑定数据方面非常方便,套下教程demo: <div ng-app="myApp" ng-controller="myCtrl"> 名字: <input ng-model="name"> <h1>你输入了: {{name}}</h1> </div> 我就想着,使用jq/js怎么实现类似的效果,后来找找,发现使用propertychan

  • JS数据双向绑定原理与用法实例分析

    本文实例讲述了JS数据双向绑定原理与用法.分享给大家供大家参考,具体如下: 通常在前端开发过程中,经常遇到需要绑定两个甚至多个元素之间的值,比如将input的值绑定到一个h1上,改变input的值,h1的文字也自动更新. <h1 id="title">Hello</h1> <input type="text" id="a" /> 首先是在界面上更改input的值,需要监听input的"input&qu

  • JS原生数据双向绑定实现代码

    代码如下: <span style="font-family:Times New Roman;font-size:14px;" deep="7"><!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Demo</title> <script> fu

  • AngularJS双向绑定和依赖反转实例详解

    AngularJS双向绑定和依赖反转 一.双向绑定: UI<-->数据 数据->UI (数据改变UI跟着变) UI->数据 (UI改变数据跟着变) 数据改变->UI改变原理: 监听数据是否改变,如果改变更新UI数据. UI改变->数据改变原理: <html> <body> <input type="text" name="name" value="" id="text1&

随机推荐