要提到MVVM,则不得不提到在它之前出现的另一种软件架构--MVC。
在MVC中:
M--Model: 即数据模型(想象它将送到数据库中被存储起来)
V--View: 即视图(或者将其理解为人们看到的界面)
C-Controller: 即控制器(将信息从M中取出随后展示在V上,或反之将V上的交互数据存储到M中)
从图中可以看到在VC中存在着更多的逻辑,尽管精简代码,在功能不断增加后,项目维护、修改的工作量就不免增加,同时由于C是通过代码进行控制的,不同编码人员的编码逻辑、编码风格等都会对它的复用性、健壮性产生影响。
随着MVC出现问题,人们开始寻找问题的解决途径,而MVVM就是其中一种。
在MVVM中:
M-Model
V-View
VM-ViewModel,与View紧密相关的数据模型(就像是某个页面的私有变量),View的显示(如Loading图标显示)直接与之相关(如一个VM: isLoading 数据),所有的操作只与VM相关而不直接操作View
在MVVM的页面中,存在一个输入框A,一个文本标签B,它们的值都与VM中的数据项content绑定,当用户在A中输入"123"时,通过双向绑定(也是一些事件实现,比如onChange),VM中对应的数据项content将由""-->"123",而此时与之绑定的B中的值也会变成"123"。这里讨论到的是使用了双向绑定的情况,在这个过程中,我们其实没有使用事件(即C),但其实C(Controller)并没有消失,而是在MVVM框架中进行了封装。
<input v-model="message"> // 输入框A
<p>{{ message }}</p> // 文本标签B
// 在Vue对象中
new Vue({
...
data:{
message:""
}
})
// 如果一直追溯,则data即是VM,但它还需要框架中的其他部分的帮助,才能实现作为VM的功能(如双向绑定)
其实在双向绑定中,我们已经不太能看到C的存在了(但它仍存在于框架中!只是被封装而对于开发者透明了),接下来我们再谈论单向绑定的情况:
在MVVM页面中,存在一个按钮A,文本标签B,通过点击A,我们将改变VM中的content的值,而B的值与content绑定。则,点击A将会改变content的值,从而引起B的值的改变。在这里,VM中的content改变了,View在框架的作用下进行自动更新。
<button v-on:click="getMessage">获得消息</button> // A
<p>{{ message }}</p> // B
new Vue({
...
data:{
message:""
},
methods:{
getMessage: function() {
this.message = "new message"
}
}
})
通过上述的例子、代码,我们可以发现,维护、修改这些代码时,V\VM部分区分得较为清晰,在MVC中制造困难的C已经被隐藏在其中或是减少了。MVVM模式除了将开发者的注意力集中在VM中外,同时还提供了统一的事件处理(可以想象一下一个经典问题:往页面的表格中插入100条数据,难免会有人一条一条地插入而不使用批量更新策略,特别是当这个需求是由原本的插入1条不断增加时)、编码规范等,更有利于维护、修改。
所以相对于MVC,在一定规模的应用中,MVVM带来了更简洁清晰的代码、统一的策略、明确的规范等,加强了项目的健壮性、可维护性,同时在一些诸如批量更新的问题中附加了优质的解决方案从而能让开发者更专注于实现产品的功能。