文中应用到的数据名词:

MVVM   ------------------        视图-----模型----视图模型                三者与 Vue 的对应:view 对应 templatevm 对应 new Vue({…})model 对应 data

nodeType       判断节点是否是元素节点

querySelector    创建一个元素节点

createDocumentFragment     文档碎片

attributes      获取元素属性集合

textContent   获取文本内容

reduce( prev,next,currentIndex){}               一个可以用上一个元素和当前元素做处理的方法

defineProperty(obj,key,value){}                数据拦截的主要方法

MVVM响应式实现原理:

1.模板编译

2.数据劫持

3.watcher

首先建立一个vue的实例,建立mvvm.js ,构建 mvvm类。  获取el的节点 和 data   放入实例中,在将Observer.js(数据劫持)和Compile.js(模板编译) 放入mvvm的js   ,全部在index页面运行.

第一步:模板编译

我首先制作Compile.js ,也就是模板编译  。

首先需要获取el 这个属性的值   用nodeType === 1判断是不是元素节点. 如果不是则用 queryselector() 生成一个节点 。  这样做的目的是,有些人el:#app  有些人是document.getElementById('app')。 不管俩者如何,我们都要生成一个节点来供后续使用。

随后判断el节点是否存在,如果存在。则进行编译 ,  这里编译最好不要在dom里进行遍历编译,非常耗性能 。 我推荐的是用 createDocumentFragment() 方法. 建立一个虚拟节点对象, 在这个虚拟节点对象里进行遍历以及对应的操作。

那么说到虚拟节点, 我们需要将我们获取的el节点整个放入进去 ,进行遍历,将app里的每一个子节点都搬到fragement 变量中。

然后进行节点的编译。这里的节点又分为元素节点和文本节点。 还是用刚刚的nodeType判断区分吗,然后做对应的操作。

接下来我们先编译元素节点  首先我们需要知道,获取元素节点要做什么,为什么获取元素节点。 我是希望通过获取元素节点上的关于vue的指令,比如:v-model,v-html,v-for 。等等...   那么这些指令是放在元素节点上的属性里,所以我们用 attributes 获取元素节点的属性名的集合 ,也就是我们说的v-model 。通过遍历这个attr属性名的集合,获取每个属性名。通过isDirective函数判断attrName包含 v-  的属性,这里我做给假设,好方便理解。 这里通过上面的过滤,可以得出attrName 是一个指令名。那我假设这个指令名为v-model。 我首先获取v-model的值,也就是expr。然后做一个解耦对象CompileUtil ,方便后面制作其他的指令。所以这里调用的是CompileUtil[model]{node,this.v,,expr};

 

调用model的指令后,在model这个函数里做相对应的处理。这里的watcher构造函数先不用管,后面的事情。 这里的uptate['modelUptate']和model一样放在CompileUtil 中,方便管理。 如果updateFn存在的话,则执行updateFn(),将v-model的值赋予input节点的value.下图中的getVal 是防止 v-model=’messge.a' 这种嵌套对象的。这个函数里,首先利用split将messge.a 拆分成[messge,a] 数组。然后利用reduce方法   放回 上一个元素[当前元素],而最下面的vm.$data 是reduce方法遍历的初始值。也就是 data 。

因为data:{ messge:{ a:'hello.world'  }   }.这样的编译,元素节点就可以编译出来了,可以将data的值编译到元素节点上了。

  

接下来编译文本节点,那文本节点,我们首先获取文本节点里的值,然后利用正则的test找{{ a }} , 和之前的元素节点一样,执行对应的函数。,执行对应的行数。这里第86-90 可以先不管,不过这里的textVal和上面的getVal 函数不一样,首先是需要将符合条件的元素里的变量取出来  也就是 {{   a  }}里的a ,argments[1] 就是a变量  。 在考虑到对象嵌套,就执行上面的getVal。然后就可以将data里的值替换到文本里了。

这样元素节点和文本节点都编译完成了。然后将整个虚拟节点丢回dom树里去 。MVVM的编译就结束了

第二步:数据劫持,函数很少。但比较绕.这里执行observe,利用递归遍历,将data里的键值对全部拿出来处理,执行defineReactive函数,这里18行可以先不看。 看下面的最重点的Object.defineProperty()。这里要传入劫持的对象,劫持的键,以及回调函数。这里回调函数里俩个参数在下图。

然后,get函数是取值是做对应的操作,set函数是设置值做对应的操作。至此数据劫持就完成了

第三步:watcher 监察者 ,一旦变化执行对应的操作。也就是将模板编译和数据劫持俩个函数联系在一起。有衔接。

这里创建watcher类,将需要的参数获取。 vm是实例,expr是值,cb是回调函数callback。watcher实例里的value = get方法的返回值,value执行一次嵌套处理返回。这里监察者作用主要是 一 更新值,二是执行callback回调函数cb。三将自己的实例,放入dep的target里。那么watcher监察者就制作好了。

最后的连接部分,首先data里的每个属性值都被加上了set和get

获取值

在最开始编译的时候,编译节点的文本节点处理和元素节点处理的时候执行watcher函数,在watcher函数里的get函数中将 watcher函数自己放入dep的target中。然后也在访问值的时候,则会执行get函数,将 每个watcher放入dep数组中 。

修改值

在修改值的时候,会触发Observer.js 的defineProperty的set函数,set函数里比较新的值和旧的值,value是编译时候的值,newValue是set函数的第一个参数,也就是修改后的新值 。   将俩者比较,如果不同,就执行Dep构造函数的notify函数。notify则会遍历全部存在的dep数组里的watcher的update方法。在watcher的update方法中,比较值的不同,如果不同就则执行回调函数,将视图更新。这个回调函数是嵌套在处理文本节点和元素节点的方法里。

 

v-model的双向绑定

至于v-model的双向绑定,其实是绑定输入框的输入事件。将输入事件新的值赋值给input节点的value值,然后值的改变,执行set函数,将视图改变。视图的改变,会执行wacther的回调函数,文本节点也会重新赋值。

这就是mvvm响应式原理的实现,如果有残缺讲不清楚的地方,欢迎指出。谢谢。

手写实现vue的MVVM响应式原理的更多相关文章

  1. Vue数据绑定和响应式原理

    Vue数据绑定和响应式原理 当实例化一个Vue构造函数,会执行 Vue 的 init 方法,在 init 方法中主要执行三部分内容,一是初始化环境变量,而是处理 Vue 组件数据,三是解析挂载组件.以 ...

  2. Vue 2.0 与 Vue 3.0 响应式原理比较

    Vue 2.0 的响应式是基于Object.defineProperty实现的 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 prop ...

  3. vue 数据劫持 响应式原理 Observer Dep Watcher

    1.vue响应式原理流程图概览 2.具体流程 (1)vue示例初始化(源码位于instance/index.js) import { initMixin } from './init' import ...

  4. vue学习之响应式原理的demo实现

    Vue.js 核心: 1.响应式的数据绑定系统 2.组件系统. 访问器属性 访问器属性是对象中的一种特殊属性,它不能直接在对象中设置,而必须通过 defineProperty() 方法单独定义. va ...

  5. 学习 vue 源码 -- 响应式原理

    概述 由于刚开始学习 vue 源码,而且水平有限,有理解或表述的不对的地方,还请不吝指教. vue 主要通过 Watcher.Dep 和 Observer 三个类来实现响应式视图.另外还有一个 sch ...

  6. vue核心之响应式原理(双向绑定/数据驱动)

    实例化一个vue对象时, Observer类将每个目标对象(即data)的键值转换成getter/setter形式,用于进行依赖收集以及调度更新. Observer src/core/observer ...

  7. Vue.js响应式原理

      写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出. 文章的原地址:answershuto/learnV ...

  8. Vue 数据响应式原理

    Vue 数据响应式原理 Vue.js 的核心包括一套“响应式系统”.“响应式”,是指当数据改变后,Vue 会通知到使用该数据的代码.例如,视图渲染中使用了数据,数据改变后,视图也会自动更新. 举个简单 ...

  9. 手摸手带你理解Vue响应式原理

    前言 响应式原理作为 Vue 的核心,使用数据劫持实现数据驱动视图.在面试中是经常考查的知识点,也是面试加分项. 本文将会循序渐进的解析响应式原理的工作流程,主要以下面结构进行: 分析主要成员,了解它 ...

随机推荐

  1. tensorflow(二)

    使用图来表示计算任务 在被称之为session的上下文中执行图 使用tensor表示数据 通过变量来维护状态 使用feed和fetch可以为任意的操作复制或者从其中获取数据 tensorflow是一个 ...

  2. [HNOI2006]最短母串问题(AC自动机+状态压缩+bfs)

    快要THUSC了,来水几道模板题吧. 这题其实是AC自动机模板.看到长度最短,首先就想到AC自动机.那么就直接暴力法来吧,把每个串建立在AC自动机上,建立fail指针,然后由于n<=12,可以把 ...

  3. 迅为IMX6Q开发板提供原理图_底板PCB_驱动程序源码_芯片和LCD数据手册_开发板环境_使用手册

      迅为IMX6开发板: Android4.4/6.0系统  Linux + Qt5.7系统  Ubuntu12.04系统 部分案例:HMI:3D打印机:医疗设备:工控机:触控一体机:车载终端 核心板 ...

  4. 搭建WordPress个人博客

    1. 准备LNMP环境 LNMP 是 Linux.Nginx.MySQL 和 PHP 的缩写,是 WordPress 博客系统依赖的基础运行环境.我们先来准备 LNMP 环境 安装Nginx 使用 y ...

  5. 53)PHP,类的继承

    详见   视频第十七天  中的第二节 类的继承 所以   类之间的继承就是一种新的关系的建立,并不是将父类的东西重新复制给子类--------------------- 当你实例化一个类的时候,调用它 ...

  6. aws基础架构学习笔记

    文章大纲 Aws 的优势 架构完善的框架(WAF) Aws 学习笔记 Aws架构中心 Aws 的优势 4.速度优势 5.全球优势 数分钟内实现全球部署 Aws全球基础设施 Aws 数据中心 来自多家O ...

  7. 系统学习javaweb补充1----HTML常用语句

    HTML 常用语句 一.单行文本框语法格式 <input type="text" name="输入信息的名字" value="输入信息的值&qu ...

  8. Linux磁盘空间满的诡异问题解决方案

    问题描述: 今天登上一台服务器,df -h 发面根目录磁盘已经满了 解决过程: cd / du -sh *  发现并没有大文件,占用的空间没多大 根据经验,先通过lsof | grep deleted ...

  9. Normally Distributed|

    6.1Introducing Normally Distributed Variables Why the word “normal”? Because, in the last half of th ...

  10. ios Alamofire网络插件的使用

    pod 'Alamofire' import Alamofire let headers:HTTPHeaders = [ "aa":"bb" ] let par ...