在认识MVVM时,先来了解一下什么是MVC
1、MVC定义
M(Model):模型,用来存储数据,将新的数据发送至View,用户得到反馈
V (View): 视图,传送指令到Controller,用来展示UI界面和响应用户交互
C(Controller):控制器,监听模型数据的改变和视图行为、处理用户交互
基于分层的目的,让彼此的职责分开,是单向通信,View一般用Controller来和Model进行联系
2、MVVM定义
随着前端的项目越来越大,MVC框架已经无法满足和解决开发需求
-
随着开发者在代码中大量调用相同的DOM API,处理繁琐,操作冗余,代码难以维护;
-
大量的DOM操作使页面渲染性能降低,加载速度变慢,用户体验差;
-
难以维护复杂多变的数据状态,当Model频繁发生变化,开发者需要主动更新到View;当用户的操作导致View发生变化,开发者同样需要将变化的数据同步到Model中
M(Model):模型
V(View):视图
VM(ViewModel):视图模型,MVVM模式的核心,是连接view和model的桥梁
View的变化会自动更新到ViewModel,ViewModel的变化会自动同步到View上,通过数据来显示视图层
当Model的数据变化,VM会监听到自动渲染到页面;当View上页面变化时,自动同步到Model中;从而实现了数据的双向绑定
优点:
- 低耦合:View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候,Model可以不变,当Model变化时,View也可以不变
- 可重用性:可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑
- 独立开发:开发人员可以专注于业务逻辑和数据的开发,设计人员专注于页面的设计
3、vue的双向数据绑定原理
响应式就是双向绑定,vue是MVVM框架,最核心就是数据驱动视图,当数据改变时,vue内部监听数据变化然后更新视图
实现数据绑定有几种方式:发布者-订阅者模式(backbone.js)、脏值检查(angular.js)、数据劫持(vue.js)
【发布者-订阅者模式】
更新数据方式的做法通常是vm.set('property',value)
【脏值检查】
angular通过脏值检测的方式比对数据是否有变更,来决定是否更新视图。通过定时轮询检测数据变动,指定的事件(DOM事件、XHR响应事件、浏览器Location变更事件、Timer事件)
【数据劫持】
vue2是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()劫持各个属性的setter、getter。在数据变动时发布信息给订阅者,触发相应的监听回调
- 实现一个数据监听器Observer,能够对数据对象的所有属性进行监听(对数据对象进行递归遍历),如有变动可拿到最新值并通知订阅者
- 实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数(添加监听数据的订阅者)
- 实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
因为Object.defineProperty()无法监听属性的添加和删除、数组索引和长度的变更,vue3选择使用了更快的原生Proxy
Proxy对象用于定义基本操作的自定义行为,在对目标对象的操作之前提供了拦截,可以外外界的操作进行过滤和改写,修改某些操作的默认行为,不是直接操作对象本身,而是操作对象的代理对象来间接操作对象
4、MVC与MVVM的代码示例
做一个简单的盒子显示与隐藏的效果,点击触发切换div的显示与隐藏
<HTML>
<MVC>
<MVVM>