一. MVVM

MVVM 是 Model - View - ViewModel 的缩写 可以看到他和之前的MVC很像,的确有人称之为一个加强优化版的MVC. 是一种模块化开发代码分层的思想或者框架;
MVVM 的优点
1、主要目的是分离视图(View)和模型(Model)
2、降低代码耦合,提高视图或者逻辑的重用性。
3、提高了模块的可测试性
模型(Model): 模型和业务数据绑定,方便数据的使用和传递;
视图(View): 视图是应用程序中用户界面相关的部分,是用户看到并与之交互的界面。
ViewModel: ViewMode是数据和视图的中介连接。 首先它的创建需要将Model中的数据绑定在他身上。将原来MVC中的业务逻辑剥离出来 写在ViewModel中,简化view 、和 controller。
更改数据,视图也会发生相应的改变.
在这里插入图片描述

二.响应式原理

官网概述:当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。
每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
在这里插入图片描述

const obj = {};

let initValue = 'kongzhi';

Object.defineProperty(obj, 'name', {
  // 当我们使用 obj.name 获取该值的时候,会自动调用 get 函数
  get: function() {
    return initValue;
  },
  set: function(value) {
    initValue = value;
  }
});

// 我们来获取值,会自动调用 Object.defineProperty 中的 get函数方法。

console.log(obj.name); // 打印出kongzhi

// 设置值的话,会自动调用 Object.defineProperty 中的 set方法。
obj.name = 'xxxxx';

console.log(obj.name); // 打印出 xxx

Object.defineProperty的缺陷:

  1. 无法检测到对象属性的新增或删除。
  2. 无法监听数组变化 。

Object.defineProperty和Proxy区别:

  1. Proxy使用上比Object.defineProperty方便的多。
  2. Proxy代理整个对象,Object.defineProperty只代理对象上的某个属性。
  3. 如果对象内部要全部递归代理,则Proxy可以只在调用时递归,而Object.defineProperty需要在一开始 就全部递归,Proxy性能优于Object.defineProperty。
  4. vue中,Proxy在调用时递归,Object.defineProperty在一开始就全部递归,Proxy性能优于Object.defineProperty。
  5. 对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到。
  6. 数组新增删除修改时,Proxy可以监听到,Object.defineProperty监听不到。
  7. Proxy不兼容IE,Object.defineProperty不兼容IE8及以下。

三.vnode和diff算法

什么是vnode:
vnode只是一个名字,本质上来说就是一个普通的JavaScript对象,是从VNode类实例化的对象。我们用这个JavaScript对象来描述一个真实DOM元素的话,那么该DOM元素上的所有属性在VNode这个对象上都存在对应得属性。

简单来说,vnode可以理解成节点描述对象,他描述了应该怎样去创建真实的DOM节点。
例如,tag表示一个元素节点的名称,text表示一个文本节点的文本,children表示子节点等。vnode表示一个真实的DOM元素,所有真实的DOM节点都是用vnode创建并插入到页面中。
diff算法 :
diff算法是通过同层的树节点进行比较而非对树进行逐层搜索遍历的方式,时间复杂度只有O(n);
diff算法通过比较该层的树节点,当不同的时候,根据不同情况替换节点,当相同的时候判断新的虚拟树和原虚拟树是否都有子节点,有的话进入下一层进行比较。
网上找的图片
在这里插入图片描述
diff算法的实现:patch函数(有两种情况,一种是首次加载,还有就是新旧节点patch)
首次加载页面 执行patch (参数1,参数2),参数1是创建的接收vnode的容器。参数2是vnode。
第二次加载或者之后修改执行 执行patch (参数1,参数2)参数1是创建的接收 老的vnode。参数2是新的vnode。

diff的原理

:遍历新旧虚拟dom节点进行对比。首先会通过四种判断规则进行优化判断,这四种判断分别是:
(1)旧虚拟dom顶部节点与新虚拟dom顶部节点进行节点比较,如果节点相同则进行patch虚拟节点操作,并且虚拟dom起始索引+1,新虚拟dom起始索引+1
(2)旧虚拟dom尾部节点与新虚拟dom尾部节点进行比较,如果节点相同则进行patch虚拟节点操作,并且虚拟dom结尾索引-1,新虚拟dom起始索引-1
(3)旧虚拟dom顶部节点与新虚拟dom尾部节点进行节点比较,如果节点相同则进行patch虚拟节点操作,并且虚拟dom起始索引+1,新虚拟dom结尾索引-1
(4)就虚拟dom尾部节点与新虚拟dom头部节点进行节点比较,如果节点相同则进行patch虚拟节点操作,并且虚拟dom尾部索引-1,新虚拟dom头部索引+1
当四种优化算法都不符合时:则会通过遍历查找新开始节点在老节点中的索引位置(1)如果老节点中没有找到新节点,则说明是新创建的元素,执行创建操作。
(5)如果老节点中找到了新节点,则判断新旧节点是否为同一个节点,如果是同一个节点则执行patch虚拟节点操作,并且将找到的旧虚拟节点设置为undefined,以及将找到的旧的虚拟节点插入到日起始节点位置
(6)如果老节点中找到了新节点,判断新旧节点不为同一个节点,则视为新节点,进行创建操作。
当新旧节点遍历结束后,如果旧节点起始位置大于旧节点结束位置,则证明有旧节点遍历完,新节点有剩余,剩余的新节点执行新增操作,如果新节点起始位置大于新节点结束位置,则证明新节点遍历完,l旧节点有剩余,剩余的旧节点执行删除操作

模板编译

在这里插入图片描述

vue template模板编译的过程经过parse()生成ast(抽象语法树),optimize对静态节点优化,generate()生成render字符串
之后调用new Watcher()函数,用来监听数据的变化,render 函数就是数据监听的回调所调用的,其结果便是重新生成 vnode。
当这个 render 函数字符串在第一次 mount、或者绑定的数据更新的时候,都会被调用,生成 Vnode。
如果是数据的更新,那么 Vnode 会与数据改变之前的 Vnode 做 diff,对内容做改动之后,就会更新到我们真正的 DOM
在这里插入图片描述

vue渲染过程

vue的整个实现流程

  1. ·第一步∶解析模板成render 函数
  2. 第二步:响应式开始监听
  3. 第三步︰首次渲染,显示页面,且绑定依赖·第四步: data 属性变化,触发rerender

第一步∶解析模板成render 函数:
使用with 的用法
模板中的所有信息都被render函数包含
模板中用到的data 中的属性,都变成了JS变量·模板中的v-model v-for v-on都变成了JS逻辑o render 函 数返回vnode
第二步:响应式开始监听
第三步:首次渲染,显示页面,且绑定依赖
data中有很多属性,有些被用到,有些可能不被用到·被用到的会走到get ,不被用到的不会走到get未走到get中的属性,set的时候我们也无需关心·避免不必要的重复渲染
第四步:data属性变化
修改属性,被响应式的set 监听到
set中执行updateComponent
updateComponent重新执行vm._render()
生成的vnode和prevVnode ,通过patch 进行对比·渲染到 html中

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐