前端⾯试题:这是我理解的MVVM,请注意查收
MVVM模式是什么?你是怎么理解MVVM原理的?理解它不只是应付⾯试,对VUE、Backbone.js、angular、Ember、avalon框架的设计模式也会有更进步⼀步的理解,有可能下⼀个流⾏框架就是你的杰作~~本篇⽂章最后也会实现了⼀个属于⾃⼰的简易MVVM库,⾥⾯实现了⼀个mvvm库应有基本功能~
vue、react、angular了,在投递简历时,我们都可以看到任职要求会有最少熟悉这些框架中的 现在流⾏的前端框架也就是
现在流⾏的前端框架也就是 vue、react、angular了,在投递简历时,我们都可以看到任职要求会有最少熟悉这些框架中的⼀种,掌握这些框架就好像时多了⼀个轮⼦或者说是多了⼀个车,框架可以然我们快速的使⽤、复⽤处理⼀些问题。当然⾯试中不仅会问到这些只是的掌握情况,也会问些你的框架的理解,因为知其然也要知其所以然,我们这篇⽂章来了解MVVM框架模式~如果⽂章有问题,也请⼤家指正,不要打我啊~~
⼀、MVVM的概念
Mvvm定义MVVM是Model-View-ViewModel的简写。是⼀个软件架构设计模式,由微软 WPF 和 Silverlight 的架构师 Ken Cooper 和Ted Peters 开发,是⼀种简化⽤户界⾯的事件驱动编程⽅式。由 Joh
n Gossman(同样也是 WPF 和 Silverlight 的架构师)于2005年在他的博客上发表。即模型-视图-视图模型。
⼆、MVVM的发展史
在了解MVVM之前,我们先回顾⼀下前端发展的历史。下⾯⼀趴是来 ⾃廖雪峰官⽅⽹站的内容,了解历史就会知道为啥MVVM会被使⽤,使⽤背景,当然也可以跳过直接看下⼀趴~
在上个世纪的1989年,欧洲核⼦研究中⼼的物理学家Tim Berners-Lee发明了超⽂本标记语⾔(HyperText Markup Language),简称HTML,并在1993年成为互联⽹草案。从此,互联⽹开始迅速商业化,诞⽣了⼀⼤批商业⽹站。
最早的HTML页⾯是完全静态的⽹页,它们是预先编写好的存放在Web服务器上的html⽂件。浏览器请求某个URL时,Web服务器把对应的html⽂件扔给浏览器,就可以显⽰html⽂件的内容了。jsp用什么前端框架
如果要针对不同的⽤户显⽰不同的页⾯,显然不可能给成千上万的⽤户准备好成千上万的不同的html⽂件,所以,服务器就需要针对不同的⽤户,动态⽣成不同的html⽂件。⼀个最直接的想法就是利⽤C、C++这些编程语⾔,直接向浏览器输出拼接后的字符串。这种技术被称为CGI:Common Gateway Interface。
很显然,像新浪⾸页这样的复杂的HTML是不可能通过拼字符串得到的。于是,⼈们⼜发现,其实拼字符串的时候,⼤多数字符串都是HTML⽚段,是不变的,变化的只有少数和⽤户相关的数据,所以,⼜出现了新的创建动态HTML的⽅式:ASP、JSP和PHP——分别由微软、SUN和开源社区开发。
在ASP中,⼀个asp⽂件就是⼀个HTML,但是,需要替换的变量⽤特殊的<%=var%>
标记出来了,再配合循环、条件判断,创建动态HTML就⽐CGI要容易得多。
但是,⼀旦浏览器显⽰了⼀个HTML页⾯,要更新页⾯内容,唯⼀的⽅法就是重新向服务器获取⼀份新的HTML内容。如果浏览器想要⾃⼰修改HTML页⾯的内容,就需要等到1995年年底,JavaScript被引⼊到浏览器。
有了JavaScript后,浏览器就可以运⾏JavaScript,然后,对页⾯进⾏⼀些修改。JavaScript还可以通过修改HTML的DOM结构和CSS来实现⼀些动画效果,⽽这些功能没法通过服务器完成,必须在浏览器实现。
⽤JavaScript在浏览器中操作HTML,经历了若⼲发展阶段:
第⼀阶段,直接⽤JavaScript操作DOM节点,使⽤浏览器提供的原⽣API:
var dom = ElementById('name');
dom.innerHTML = 'Homer';
lor = 'red';
复制代码
第⼆阶段,由于原⽣API不好⽤,还要考虑浏览器兼容性,jQuery横空出世,以简洁的API迅速俘获了前端开发者的芳⼼:
$('#name').text('Homer').css('color', 'red');
第三阶段,MVC模式,需要服务器端配合,JavaScript可以在前端修改服务器渲染后的数据。
现在,随着前端页⾯越来越复杂,⽤户对于交互性要求也越来越⾼,想要写出Gmail这样的页⾯,仅仅⽤jQuery是远远不够的。MVVM模型应运⽽⽣。
MVVM最早由微软提出来,它借鉴了桌⾯应⽤程序的MVC思想,在前端页⾯中,把Model⽤纯JavaScript对象表⽰,View负责显⽰,两者做到了最⼤限度的分离。
把Model和View关联起来的就是ViewModel。ViewModel负责把Model的数据同步到View显⽰出来,还负责把View的修改同步回Model。
ViewModel如何编写?需要⽤JavaScript编写⼀个通⽤的ViewModel,这样,就可以复⽤整个MVVM模型了。
三、正式的MVVM理解
MVVM模式
MVVM 的核⼼是 ViewModel 层,它就像是MVVM 的出现促进了 GUI 前端开发与后端业务逻辑的分离,极⼤地提⾼了前端开发效率。MVVM 的核⼼是 ViewModel 层
⼀个中转站(value converter),负责转换 Model 中的数据对象来让数据变得更容易管理和使⽤,该层向上与视图层进⾏双向数据绑定,向下与 Model 层通过接⼝请求进⾏数据交互,起呈上启下作⽤。如下图所⽰:
MVVM组成部分
MVVM组成部分
# View 层
View 是视图层,也就是⽤户界⾯。前端主要由 HTML 和 CSS 来构建,为了更⽅便地展现 ViewModel 或者 Model 层的数据,已经产⽣了各种各样的前后端模板语⾔,⽐如FreeMarker、Marko、Pug、Jinja2等等,各⼤ MVVM 框架如 avalon,Vue,Angular 等也都有⾃⼰⽤来构建⽤户界⾯的内置模板语⾔。
# Model 层
Model 是指数据模型,泛指后端进⾏的各种业务逻辑处理和数据操控,主要围绕数据库系统展开。
后端业务处理在这就不多赘述了,其实前端⼈员⼤多都不需要管,只要后端保证对外接⼝⾜够简单就⾏了,我请求api,你把数据返出来,咱俩就这点关系,其他都扯淡。
# ViewModel 层
ViewModel 是由前端开发⼈员组织⽣成和维护的视图数据层。mvvm模式的核⼼,它是连接view和model的桥梁。在这⼀层,前端开发者对从后端获取的 Model 数据进⾏转换处理,做⼆次封装,以⽣成符合 View 层使⽤预期的视图数据模型。需要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和⾏为两部分,⽽ Model 层的数据模型是只包含状态的,⽐如页⾯的这⼀块展⽰什么,那⼀块
展⽰什么这些都属于视图状态(展⽰),⽽页⾯加载进来时发⽣什么,点击这⼀块发⽣什么,这⼀块滚动时发⽣什么这些都属于视图⾏为(交互),视图状态和⾏为都封装在了 ViewModel ⾥。这样的封装使得 ViewModel 可以完整地去描述 View 层。由于实现了双向绑定,ViewModel 的内容会实时展现在 View 层,这是激动⼈⼼的,因为前端开发者再也不必低效⼜⿇烦地通过操纵 DOM 去更新视图,MVVM 框架已经把最脏最累的⼀块做好了,我们开发者只需要处理和维护 ViewModel,更新数据视图就会⾃动得到相应更新,真正实现数据驱动开发。看到了吧,View 层展现的不是 Model 层的数据,⽽是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,这个解耦是⾄关重要的,它是前后端分离⽅案实施的重要⼀环。
MVVM设计模式的优缺点:
优点:
1、当然是最主要的双向绑定技术,
单向绑定与双向绑定。
当然是最主要的双向绑定技术,单向绑定与双向绑定。
所谓 “
“单向绑定”就是ViewModel变化时,⾃动更新View
所谓
“双向绑定”就是在单向绑定的基础上View变化时,⾃动更新ViewModel
所谓 “
所谓
我们可以先观察下MVVM框架和jQuery操作DOM相⽐有什么区别?
原来的html
<p>Hello, <span id="name">LEE</span>!</p><p>You are <span id="age">18</span>.</p>
展⽰
⽤jQuery修改name和age节点的内容:
var name = '修改';
var age =100;
$('#name').text(name);
$('#age').text(age);
复制代码
如果我们使⽤MVVM框架来实现同样的功能,我们⾸先并不关⼼DOM的结构,⽽是关⼼数据如何存储。最简单的数据存储⽅式是使⽤:
var person = {
name: 'LEEt',
age: 18
};
复制代码
我们把变量person看作Model,把HTML某些DOM节点看作View,并假定它们之间被关联起来了。
要把显⽰的name从LEE改为修改,把显⽰的age从18改为100,我们并不操作DOM,⽽是直接修改JavaScript对象:
person.name = '修改';
person.age = 100;
复制代码
这样可以看出,我们的关注点从如何操作DOM变成了如何更新JavaScript对象的状态,⽽操作JavaScript对象⽐DOM简单多了!
DOM的状态,从⽽把发者从操作
框架去⾃动更新DOM
DOM的繁琐步骤中解脱出
的繁琐步骤中解脱出
的状态,从⽽把发者从操作DOM
Model的变化,让
MVVM框架去⾃动更新
MVVM的设计思想:关注
MVVM
的设计思想:关注Model
的变化,让MVVM
来!
2、由于控制器的功能⼤都移动到View上处理,⼤⼤的对控制器进⾏了瘦⾝。
3、可以对View或ViewController的数据处理部分抽象出来⼀个函数处理model。这样它们专职页⾯布局和页⾯跳转,它们必然更⼀步的简化。
4、提⾼可维护性
5、可测试。界⾯素来是⽐较难于测试的,⽽现在测试可以针对ViewModel来写。
6、低耦合可重⽤:视图(View)可以独⽴于Model变化和修改,⼀个ViewModel可以绑定不同的"View"上,当View变化的时候Model不可以不变,当Model变化的时候View也可以不变。你可以把⼀些视图逻辑放在⼀个ViewModel⾥⾯,让很多view重⽤这段视图逻辑。
缺点:
1. Bug很难被调试。因为使⽤双向绑定的模式,当你看到界⾯异常了,有可能是你View的代码有Bug,也可能是Model的代码有问题。
数据绑定使得⼀个位置的Bug被快速传递到别的位置,要定位原始出问题的地⽅就变得不那么容易了。另外,数据绑定的声明是指令式地写在View的模版当中的,这些内容是没办法去打断点debug的。
2. ⼀个⼤的模块中model也会很⼤,虽然使⽤⽅便了也很容易保证了数据的⼀致性,当时长期持有,不释放内存就造成了花费更多的内
存。
3. 对于⼤型的图形应⽤程序,视图状态较多,ViewModel的构建和维护的成本都会⽐较⾼。
MVVM的适⽤范围
从⼏个例⼦我们可以看到,MVVM最⼤的优势是编写前端逻辑⾮常复杂的页⾯,尤其是需要⼤量DOM操作的逻辑,利⽤MVVM可以极⼤地
简化前端页⾯的逻辑。
但是MVVM不是万能的,它的⽬的是为了解决复杂的前端逻辑。对于以展⽰逻辑为主的页⾯,例如,新闻,博客、⽂档等,不能使⽤MVVM展⽰数据,因为这些页⾯需要被搜索引擎索引,⽽搜索引擎⽆法获取使⽤MVVM并通过API加载的数据。
SEO(Search Engine Optimization)的页⾯,不能使⽤MVVM展⽰数据。不需要SEO的页⾯,如果前端逻辑复
所以,需要 SEO(Search Engine Optimization)的页⾯,不能使⽤MVVM展⽰数据。不需要SEO的页⾯,如果前端逻辑复
所以,需要
杂,就适合使⽤MVVM展⽰数据,例如,⼯具类页⾯,复杂的表单页⾯,⽤户登录后才能操作的页⾯等等。当然可能现在有了ssr。
常⽤的MVVM框架有:
Angular:Google出品,名⽓⼤,但是学习难度有些⼤;适合PC,代码结构会⽐较清晰;
Backbone.js:⼊门⾮常困难,因为⾃⾝API太多;
Ember:⼀个⼤⽽全的框架,想写个Hello world都很困难。
Avalon:属于轻量级的,并且对⽼的浏览器⽀持程度较⾼,最低⽀持到IE6,所以适合兼容⽼刘浏览器的项⽬;
Vue:主打轻量级,仅作为MV*中的视图部分使⽤,优点轻量级,易学易⽤,缺点是⼤项⽬的时候还要配合其他框架或者库来使⽤,⽐较⿇烦
四、实现MVVM的js库
⽬前实现数据双向绑定主要有⼀下⼏种⽅式:
1. 脏值检测(angular):
以典型的mvvm框架angularjs为代表,angular通过检查脏数据来进⾏UI层的操作更新。关于angular的脏检测,有⼏点需要了解些:
l脏检测机制并不是使⽤定时检测。
l脏检测的时机是在数据发⽣变化时进⾏。
l angular对常⽤的dom事件,xhr事件等做了封装, 在⾥⾯触发进⼊angular的digest流程。
l在digest流程⾥⾯, 会从rootscope开始遍历, 检查所有的watcher。 (关于angular的具体设计可以看其他⽂档,这⾥只讨论数据绑定),那我们看下脏检测该如何去做:主要是通过设置的数据来需与该数据相关的所有元素,然后再⽐较数据变化,如果变化则进⾏指令操作。
2.前端数据劫持(Hijacking)(vue):基本思路:通过Object.defineProperty() 去劫持数据每个属性对应的getter和setter。当有数据读取和赋值操作时则调⽤节点的指令,这样使⽤最通⽤的=等号赋值就可以了。
3.发布-订阅模式(backbone):通过发布消息,订阅消息进⾏数据和视图的绑定监听。
⽐较⽼的实现⽅式,使⽤观察者编程模式,主要思路是通过在数据对象上定义get和set⽅法等,调⽤时⼿动调⽤get或set数据,改变数据后触发UI层的渲染操作;以视图驱动数据变化的场景主要应⽤与input、select、textarea等元素,当UI层变化时,通过监听dom的change,keypress,keyup等事件来触发事件改变数据层的数据。整个过程均通过函数调⽤完成。
VUE的⼀个实现MVVM的库)
代码实现思路:(类似实现 VUE
代码实现思路:(类似实现
模拟的是VUE的MVVM库使⽤数据劫持思路实现,MVVM,上图为基本思路图。如上图所⽰,我们可以看到,整体实现分为已下步骤
1、实现⼀个Observer,对数据进⾏劫持,通知数据的变化(将使⽤的要点为:Object.defineProperty()⽅法)
2、实现⼀个Compile,对指令进⾏解析,初始化视图,并且订阅数据的变更,绑定好更新函数
3、实现⼀个Watcher,将其作为以上两者的⼀个中介点,在接收数据变更的同时,让Dep添加当前Watcher,并及时通知视图进⾏update
4、实现⼀些VUE的其他功能(Computed、menthods)
5、实现MVVM,整合以上⼏点,作为⼀个⼊⼝函数
以下为代码部分:
Html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>
实现MVVM的js库(模拟vue实现功能)</title>
<script src="./MVVM.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="person.name">
<p>
hello,{{person.name}}
</p>
<p>You are:{{person.age}}</p>
<!-- computed属性如果数据不变化视图不更新 -->
<p>{{getNewName}}</p>
<button type="button" name="button" v-on:click="testToggle">
修改名字</button>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
person: {
name: 'lee',
age: 18
}
},
methods: {
testToggle(){
this.person.name = '修改后的名字:哈哈';
}
},
computed: {
getNewName(){
return this.person.name+' 是要成为海贼王的⼈'
}
},
})
</script>
</body>
</html>
复制代码
js:
// 2019-4-4
// lee
// 草履⾍的思考
// 简单模拟vue实现MVVM
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论