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


Posted in Javascript onFebruary 05, 2020

本文实例讲述了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选择器来找到对应的节点进行更新。这也是一种替代的方案。

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

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程序设计有所帮助。

Javascript 相关文章推荐
DHTML 中的绝对定位
Nov 26 Javascript
javascript中的有名函数和无名函数
Oct 17 Javascript
jQuery插件animateSlide制作多点滑动幻灯片
Jun 11 Javascript
Ajax中解析Json的两种方法对比分析
Jun 25 Javascript
js鼠标点击按钮切换图片-图片自动切换-点击左右按钮切换特效代码
Sep 02 Javascript
jQuery动态添加及删除表单上传元素的方法(附demo源码下载)
Jan 15 Javascript
jquery点击展示与隐藏更多内容
Dec 03 Javascript
javascript设计模式之策略模式学习笔记
Feb 15 Javascript
微信小程序 密码输入(源码下载)
Jun 27 Javascript
js实现首屏延迟加载实现方法 js实现多屏单张图片延迟加载效果
Jul 17 Javascript
JavaScrip关于创建常量的知识点
Dec 07 Javascript
React diff算法的实现示例
Apr 20 Javascript
小程序如何写动态标签的实现方法
Feb 05 #Javascript
vue如何实现动态加载脚本
Feb 05 #Javascript
vue实现图片懒加载的方法分析
Feb 05 #Javascript
Vue组件基础用法详解
Feb 05 #Javascript
vue组件传值的实现方式小结【三种方式】
Feb 05 #Javascript
vue路由传参的基本实现方式小结【三种方式】
Feb 05 #Javascript
Vuex的API文档说明详解
Feb 05 #Javascript
You might like
php实现从ftp服务器上下载文件树到本地电脑的程序
2009/02/10 PHP
PHP文件读写操作之文件写入代码
2011/01/13 PHP
php的4种常见运行方式
2015/03/20 PHP
HTML中嵌入PHP的简单方法
2016/02/16 PHP
PHP基于DateTime类解决Unix时间戳与日期互转问题【针对1970年前及2038年后时间戳】
2018/06/13 PHP
phpstudy2020搭建站点的实现示例
2020/10/30 PHP
jquery animate图片模向滑动示例代码
2011/01/26 Javascript
Seajs的学习笔记
2014/03/04 Javascript
js实现点击按钮后给Div图层设置随机背景颜色的方法
2015/05/06 Javascript
javascript仿百度输入框提示自动下拉补全
2016/01/07 Javascript
javascript运算符语法全面概述
2016/07/14 Javascript
最原始的jQuery注册验证方式
2016/10/11 Javascript
js+css3制作时钟特效
2016/10/16 Javascript
jQuery实现验证码功能
2017/03/17 Javascript
Bootstrap Table 在指定列中添加下拉框控件并获取所选值
2017/07/31 Javascript
JS操作时间 - UNIX时间戳的简单介绍(必看篇)
2017/08/16 Javascript
Vue父组件调用子组件事件方法
2018/02/23 Javascript
修改vue+webpack run build的路径方法
2018/09/01 Javascript
React如何解决fetch跨域请求时session失效问题
2018/11/02 Javascript
关于React动态加载路由处理的相关问题
2019/01/07 Javascript
vue基于Echarts的拖拽数据可视化功能实现
2020/12/04 Vue.js
JavaScript代码实现微博批量取消关注功能
2021/02/05 Javascript
[46:43]DOTA2上海特级锦标赛D组小组赛#1 EG VS COL第三局
2016/02/28 DOTA
Python实现过滤单个Android程序日志脚本分享
2015/01/16 Python
python3人脸识别的两种方法
2019/04/25 Python
简单了解python反射机制的一些知识
2019/07/13 Python
Python 利用邮件系统完成远程控制电脑的实现(关机、重启等)
2019/11/19 Python
详解从Django Allauth中进行登录改造小结
2019/12/18 Python
python定义具名元组实例操作
2021/02/28 Python
国际领先的在线时尚服装和配饰店:DressLily
2019/03/03 全球购物
保密普查工作实施方案
2014/02/25 职场文书
运动会演讲稿300字
2014/08/25 职场文书
新闻人物通讯稿
2014/10/09 职场文书
个人作风纪律整顿整改措施
2014/10/25 职场文书
党建工作整改措施
2014/10/28 职场文书
安全生产先进个人事迹材料
2014/12/30 职场文书