1 MVVM模式

Model-View-ViewModel源自MVC模式,核心是ViewModel,ViewModel作为一个“中转站”,对接Model层获得并转换数据使得数据易管理、便于View层使用,又对接View层进行双向的数据绑定。MVVM框架利用ViewModel这一层帮助开发者们做好了之前jQuery时代低效的查找、操作DOM的工作。View最终展现的不仅是Model的数据,也是经过ViewModel加工后数据。

"虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示组件实例"

2 Vue双向数据绑定

从设计思想来说,Vue采用的MVVM模式是双向绑定的。Vue实例即充当MVVM中ViewModel层,Model驱动View更新,View层模板进行编译后Vue实例内部数据也会更新。从开发者使用的角度来说,Vue并没有提供类似AngularJS双向数据绑定的API。虽然它通过提供v-model这个语法糖提供了部分双向数据绑定的能力。Vue实际上是单向的数据驱动视图。

<input v-model="inputData" /> 

等价于

<input :value="inputData"  @input="inputData = $event.target.value"/>

3 数据驱动视图

视图是由数据驱动生成的,对视图的修改,不是直接操作DOM而是通过修改数据。通过利用虚拟DOM,Vue实现了数据驱动视图。整体看一下从创建Vue实例到最后渲染到页面发生的过程。如图:

数据驱动生成视图的过程:

1)初始化Vue:Vue是一个类,new Vue({...})操作调用构造函数完成合并配置、初始化生命周期、事件中心,初始化Injections、state(props|data|methods|computed|watch)、provide等;
2)挂载Vue实例到el:校验页面上的挂载点el,并拿到对应的template;
3)模板编译:由template编译出render()函数,经过一系列的compileToFunctions-createCompiler-createCompilerCreator后,最后Parse出ast,经过优化ast,最终生成render代码;
4)调用render():将自定义配置中的数据和页面模板生成的数据结合后,生成VDOM;
5)update和patch上一步的VDOM出DOM:patch提供了钩子函数,在回调中做相应的处理生成DOM。

4 响应式原理

响应式原理指的是Vue中数据变化驱动视图更新。实现的关键两个点:

1)将数据变成响应式数据
2)实现一个观察者模式:进行依赖收集和派发更新。

响应式数据是指通过代理对象的方式给数据添加上getter、setter属性特性,从而使对数据的访问、更新操作是可观测的。Vue2使用Object.defineProperty()方法,Vue3使用的是Proxy对象。再通过观察者模式,在访问数据时进行依赖的收集,在数据更新时派发通知给之前收集到的依赖做更新处理。具体来说,在Vue内部,通过Observer类将数据递归地转化成可观测对象,最终生成的响应式数据对象,是一个包含了__ob__属性的对象。在其内部定义、并调用了一系列处理函数:如walk()\defineReactive()。


依赖收集:发生在访问响应式数据触发getter函数时,收集的依赖指的是渲染Watcher,收集动作的主体即为响应式数据本身。具体来说Vue内部实现了一个管理Watcher的Dep类(内部维护了一个数组),每个响应式数据对象属性值的 getter都持有一个 dep的引用。当完成一次render调用后,会触发所有响应式数据的 getter,从而完成响应式数据Watcher的收集的过程。


派发更新:发生在更新响应式数据触发setter函数时,实际上就是把之前收集好的Watcher依赖从队列中取出来执行其update()方法的过程。其中Vue也做了一些优化,并不会每次数据改变都触发 watcher 的回调执行,而是把这些watcher先添加到一个队列里,然后在nextTick后执行 flushSchedulerQueue,利用JavaScript提供的事件队列的这种异步的方式执行更新动作。

5 Vue2和Vue3响应式原理的区别

Vue2使用Object.defineProperty(),Vue3使用的是Proxy。相比Object.defineProperty(),Proxy()不仅可以解决无法观测对象新增删除属性、无法观测数组通过索引设值、长度变化的问题,其API更为丰富。对比Object.defineProperty()观测对象的属性,Proxy代理的是对象,性能也更好。
Object.defineProperty()之所以不支持数组,是因为Vue基于性能考虑没有用,而不是因为它不支持。

参考:
Vue技术揭秘

https://ustbhuangyi.github.io...
https://www.cnblogs.com/iovec...


xizugogo
56 声望2 粉丝

千里之行,始于足下