一、架构
(一)MVC架构
MVC指的是Model-View-Controller,分别代表着模型层、视图层、控制器
Model(模型层):主要管理业务模型的数据和处理数据的逻辑
View(视图层):主要是接收用户的交互请求并展示数据信息给用户
Controller(控制器层):Model和View之间的桥梁;用于控制程序的流程。
Controller负责确保View可以访问到需求显示的Model对象的数据,View接收到用户的交互请求后,会将请求控制器转发给Controller,Controller解析请求之后,会交给对应的Model处理
(二)MVVM架构
视图模型双向绑定,是Model-View-ViewModel的缩写;MVC的改进版,把MVC中的Controller演变成ViewModel;将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开;主要目的是 为了分离视图(View)和模型(Model)的耦合
Model:数据模型
View:UI组件
ViewModel:View和Model层的桥梁
数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据
优点
- 低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上, 当View变化的时候Model可以不变,当Model变化的时候View也可以不变
- 可重用性:可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑
- 独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计
- 可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写
React既不属于MVC也不属于MVVM架构; Vue是一个灵活易用的渐进式双向绑定的MVVM框架
二、 React与Vue的不同
1、核心思想
React: 声明式渲染和组件化、单向数据流;
声明式的意思是只需要通过状态去形容最后的网页长什么样子即可;命令式指的是通过DOM操作一步步把网页变成想要的样子
组件化指的是尽可能的将页面拆分成一个个较小的、可以复用的组件,这样让我们的代码更加方便组织和管理,并且拓展性页更强。
单向数据流:数据主要从父节点通过props传递到子节点;如果某个props变化了,React会重新渲染所有的子节点;React想从一个组件去更新另一个组件的状态,需要进行状态提升;即把状态提升到他们最近的祖先组件中,触发父组件的状态变更从而影响另一个组件的显示。单向数据流的好处:能够保证状态的改变可追溯
Vue:渐进式双向绑定的MVVM框架
2、组件写法
React:JSX+inline style,把HTML和CSS全部写进JavaScript
Vue:通过template的单文件组件格式
3、响应式原理不同
React:主要是通过setState()方法来更新状态,状态更新之后,组件也会重新渲染
Vue:遍历data数据对象,使用Object。definedProperty将每个属性都转换为getter和setter,每个Vue实例都有一个对应的watcher实例,在组件初次渲染的时候会记录组件用到了哪些数据,当数据发生改变的时候触发setter方法,并通知所有依赖在这个数据的watcher实例调用update方法触发组件的compile渲染方法,进行渲染数据
4、diff算法不同
4.1 React的diff算法详解
虚拟DOM:是一个用来描述真实DOM的对象,本质是个object
Diff算法:是一种对比算法。主要对比旧的虚拟DOM和新的虚拟DOM,找出发生更改的节点,并只更新这些发生改变的节点 ,不更新未发生改变的节点,从而准确地更新DOM,减少操作真实的DOM次数,提高性能。 Diff算法是深度优先算法,时间复杂度是O(n)
调和:将Virtual DOM树转换成Actual DOM树的最少操作的过程,而diff算法是调和的具体实现
使用虚拟dom一定会真实dom快吗???? 不一定
严格的说:虚拟dom并不是比原生dom要快,更确切的说,虚拟dom是比操作不当的原生dom快
虚拟dom的优势在于:在对节点修改的时候尽量减少开销
首次渲染:不用虚拟dom的话:浏览器接受绘制指令 --> 创建所有节点;使用虚拟dom:浏览器接受绘制指令 --> 创建虚拟dom–> 创建所有节点
(1)执行过程
- React组件配合 state 创建一个虚拟DOM树
- 根据虚拟DOM树,生成一个真正的 DOM 树,再渲染到页面中
- 当 state 或者 props 变化时,根据新的数据生成一个新的虚拟DOM树
- 将新旧虚拟 DOM 树进行对比,通过diff算法找到新旧虚拟DOM的差异点,最后将差异点更新到页面上
(2)diff策略
-
策略一:(tree diff) 按照树的层级进行比较,如果该节点不存在,则整个删除,不再继续比较
question:如果节点出现了跨层级操作怎么办??? diff只简单考虑同层级的节点变化,如果跨层级就只会创建或删除节点 -
策略二:(component diff)对比每一层中的组件
(1)同一类型的两个组件 ------ 按层级比较虚拟DOM树
(2) 同一类型的两个组件,组件A变成了组件B ------ 可能虚拟DOM没有任何变化,通过shouldComponentUpdate() 来判断是否需要判断计算
(3)不同类型的组件 ------ 将一个(将被改变的)组件判断为dirtycomponent(脏组件),从而替换整个组件的所有节点 -
策略三:(element diff)如果两个组件类型相同,则需要比较组件中的元素
diff提供三种节点操作:
(1)移动:同一层级的同组子节点元素发生变化,对同一层级的同组子节点添加唯一key进行区分,从而移动
(2)插入:组件 C 不在集合(A,B)中,需要插入
(3)删除: 组件 D 在集合(A,B,D)中,但 D的节点已经更改,不能复用和更新,则删除旧的D。组件D之前在集合(A,B,D)中,但集合变成新的集合(A,B)了,则需要删除D
key的作用:为了在diff算法执行时更快的找到对应的节点,提高diff速度,更高效的更新虚拟DOM
4.2 Vue的diff算法的不同之处
- Vue对比节点,如果节点元素类型相同但className不同,认为是不同类型的元素,会进行删除重建;但是React则会认为是同类型的节点,只会修改节点属性。
- Vue的列表比对采用的是首尾指针法,React采用的是从左到右依次比对的方式;当一个集合仅需要把最后一个节点移动到了第一个,React会把前面的节点依次移动,而Vue只会把最后一个节点移动到最后一个,从这点上来说Vue的对比方式更加高效。