多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
1. mvvm是什么 2. Virtual DOM是什么 3. 前端路由时如何跳转的 4. React和Vue之间的区别 ## MVVM MVVM是什么?和MVC区别? 不管是React还是Vue,都不是MVVM框架,只是**借鉴MVVM的思路**。 * view:用户看到的视图 * Model:一般就是本地数据和数据库中的数据 基本上,通过接口从数据库中读取数据,然后将数据经过处理展现到用户看到的视图;还可以从视图读取用户的输入,然后又将用户的输入通过接口写入到数据库中。 **传统MVC架构**:使用**控制器更新模型**,**视图从模型中获取数据去渲染**。当用户有输入时,会通过控制器去更新模型,并且通知视图进行更新。 ![](https://box.kancloud.cn/4048402c30780966fa1f0f33e1c0f1c4_252x202.png) **MVC缺陷**:巨大缺陷,就是**控制器承担的责任太大**了,随着项目愈加复杂,控制器中的代码会**越来越臃肿**,导致**不利于维护**的情况。 **MVVM**:引入ViewModel概念,ViewModel**只关心数据和业务的处理**,**不关心View如何处理数据**,在这种情况下,View和Model都可以独立出来,**任何一方改变了也不一定需要改变另一方**,并且可以将一些可复用的逻辑放在一个ViewModel中,让多个View复用这个ViewModel ![](https://box.kancloud.cn/430cb79884bf019b1c66e71c9487bf63_454x187.png) 在MVVM中还引入了一个隐式的Binder层,实现了View和ViewModel的绑定 ![](https://box.kancloud.cn/2b718d485e492d489c1f308ee70139cc_529x178.png) **Vue框架**:**ViewModel就是组件的实例**。**View就是模板**,**Model的话在引入Vuex的情况下完全可以和组件分离的**。隐式的**Binder层就是Vue通过解析模板中的差值和指令**,从而实现View和ViewModel的绑定 **MVVM的精髓**:最终要的并不是通过双向绑定或者其他的方式将View与ViewModel绑定起来,而是通过**ViewModel将视图中的状态和用户的行为分离出一个抽象**,这才是MVVM的精髓。 ## Virtual DOM **什么是Virtual DOM?为什么Virtual DOM比原生DOM快?** 操作DOM慢: 因为DOM是属于**渲染引擎**中东西,而JS又是**JS引擎**中的东西,当我们通过JS操作DOM的时候,其实这个操作涉及到了**两个线程之间的通信**,那么势必会带来一些**性能上的损耗**。操作DOM一多,也就等同于**一直在进行线程之间的通信**,并且操作DOM可能还会带来**重绘回流**的情况,所以也就导致了性能上的问题。 相较于DOM来说,**操作JS对象**会快很多。 通过JS来模拟DOM ~~~ const ul = { tag: 'ul', props:{ class:'list' }, children:{ tag:'li', children:'1' } } ~~~ 上述代码对应的DOM ~~~ <ul class='list'> <li>1</li> </ul> ~~~ **DOM可以通过JS对象来模拟,反之可以通过JS对象来渲染出对应的DOM**。 通过**JS模拟DOM并且渲染出对应的DOM**只是第一步,难点在于如何**判断新旧两个JS对象的最小差异并且实现局部更新DOM**。 DOM是一个**多叉树的结构**,如果需要完整的对比两颗树的差异,需要的时间复杂度是O(n^3),这个复杂度肯定是不能接受的。 React团队优化了算法,实现了**O(n)的复杂度**来对比差异。 实现O(n)复杂度的关键:**只对比同层的节点,而不是跨层对比**,这也是考虑到实际业务中很少去跨曾的移动DOM元素。 所以判断差异算法分为了**两步**: * 首先从上至下,从左往右遍历对象,也就是**树的深度遍历**,这一步中会给每个节点**添加索引**,便于最后渲染差异。 * 一旦节点有子元素,就去判断子元素是否有不同。 **第一步算法中**:需要判断新旧节点的**tagName**是否相同,如果不相同代表节点被替换,如果没有更改tagName的话,就需要判断是否有子元素,有的话进行第二步 **第二步算法**:我们需要判断原本的列表中是**否有节点被移除**,在新的列表中需要判断**是否有新的节点加入**,还需要判断节点**是否有移动**。 举例 ~~~ //假设这里模拟一个ul,其中包含了5个li [1, 2, 3, 4, 5] //这里替换上面的li [1, 2, 5, 4] ~~~ 实际的算法中,如何去识别和改动的哪个节点呢?这就**引入了key这个属性**。 **key属性**:用来给每一个节点打标志的,用于判断是否是同一个节点 当然在判断差异的过程中,还需要**判断节点的属性是否有变化**等。 判断出以上差异,就可以把这些差异记录下来。当对比完两棵树以后,就可以**通过差异去局部更新DOM,实现性能的最优化**。 Virtual Dom的优势: 1. **提高性能** 2. 将Virtual DOM作为一个兼容层,让我们还能对接非Web端的系统,实现跨端开发(ReactNative)。 3. 同样的,通过Virtual DOM我们可以渲染到其他的平台,比如实现SSR,同构渲染等。 4. **实现组件的高度抽象化**。 ## 路由原理 **前端路由原理?两种实现方式区别?** 简单,本质是**监听URL的变化,然后匹配路由规则,显示相应的页面,并且无需刷新页面**。 目前前端使用的路由就只有两种实现方式 * Hash模式 * History模式 ### Hash模式 `www.test.com/#/`就是Hash URL,当#后面的哈希值发生变化时,可以通过**hashchange事件**来监听到URL的变化,从而进行跳转页面,并且无论哈希值如何变化,服务器接收到的URL请求永远是`www.test.com` ~~~ window.addEventListener('hashchange',()=>{ }) ~~~ Hash模式相对来说更简单,并且兼容性也好。 ### History模式 History模式是HTML5新推出的功能,主要使用`history.pushState`和`history.replaceState`改变URL。 通过History模式改变URL同样**不会引起页面的刷新**,只会**更新浏览器的历史记录**。 ~~~ //新增历史记录 history.pushState(stateObject,title,URL) //替换当前历史记录 history.replaceState(stateObject,title,URL) ~~~ 当用户做出浏览器动作时,比如点击后退按钮时会触发popState事件 ~~~ window.addEventListener('popstate', e=>{ // e.state就是pushState(stateObject) 中的stateObj console.log(e.state) }) ~~~ ### 两种模式对比 1. Hash模式只可以更改**#后面的内容**,History模式可以**通过API设置任意的同源URL**。 2. History模式可以通过API添加任**意类型的数据**到历史记录中,**Hash模式只能更改哈希值**,也就是字符串 3. **Hash模式无需后端配置,并且兼容性好**。Histroy模式在用户手动输入地址或者刷新页面的时候会发起URL请求,**后端需要配置index.html页面用于匹配不到静态资源**的时候 ## Vue和React之间的区别 1. **表单**:Vue的表单可以使用v-model支持双向绑定,相比于React来说开发商更加方便。 (v-model其实是个语法糖,本质和React写表单的方式没什么区别) 2. **改变数据**:Vue修改状态相比来说要简单很多,React需要使用setState来改变状态,并且使用这个API有一些坑点。并且Vue的底层使用了**依赖追踪**,**页面更新渲染**已经是最优的了,但是React还需要**用户手动去优化**这方面问题。 3. React 16以后,有些钩子函数会执行多次,这是引入Fiber的原因。 4. React需要使用**JSX**,有一定的上手成本,并且需要一整套的工具链支持,但是**完全通过JS来控制页面,更加的灵活**。**Vue使用了模板语法**,相比于JSX来说没有那么灵活,但完全可以**脱离工具链**,通过**直接编写render函数就能在浏览器中运行**。 5. 生态上没有多大差距,React的用户远远高于Vue 6. 上手成本:Vue一开始的定位就是尽可能的降低前端开发的门槛,然而React更多的是改变用户去接收它的概念和思想,相较于Vue来说上手成本略高。 7. React和Vue虽是两个不同的框架,但他们的底层原理都是很相似的。