MVC由三部分组成:model,view,controller。
Model(模型)
model管理应用程序的数据,model不涉及用户界面,它代表应用程序可能需要的独特形式的数据。当model改变时(如更新),它会通知它的观察者(如view视图),重新渲染出新的数据(model)。
举个例子:
假设我们有一个javascript图片库应用程序,在图片库中,一个图片可以有它自己的model(模型),这样的一种模型可能包含以下相关属性,如:图片标题,图片源地址等。一个特定的图片将存储在一个model(模型)的实例中。
var Photo = Backbone.Model.extend({ default:{ src:"example.jpg", caption:"chaojidan" }, initialize: function(){ this.set({"src",this.default.src}); } });
一个model可能有多个观察它的view。
多个model组织在一起,我们称它为集合。在集合里管理model,允许我们同时操作集合里面的所有model,无需手动观察单个model。
var PhotoGallery = Backbone.Collection.extend({ model: Photo, view : function(){ return this.filter(function(photo){ //this = collection = [Photo,Photo,.....] return photo.get("src") == "chaojidan"; }); } });
View(视图)
视图是model的可视化表示,javascript的视图是构建和维护一个DOM元素。
一个view通常检测一个model,并在model更改时,view本身能够相应的更新。
用户可以与view交互,并通过view读取和编辑model,即在model中获取和设置属性值。更新model的实际任务其实是通过controller,view会通过controller操作model。
举个例子:
我们创建一个可以创建单一图片view的函数,然后实现一个controller。
var buildPhotoView = function(photoModel, photoController){ var base = document.createElement("div"); var photoElem = document.createElement("div"); base.appendChild(photoElem); photoElem.addEventListener("click",function(){ //用户操作视图,也就是点击图片 photoController.handleEvent("click", photoModel); //控制器操作相应的model }); var render = function(){ photoElem.innerHTML = _.template("#photoTemplate", { src:photoModel.get("src") }); //使用underscore的模板库给模型生成html字符串,然后插入到photoElem中。 }; photoModel.addSubscriber(render); //render观察(其实也就是photoElem代表的view观察模型)模型photoModel,photoModel一改变,就会调用render方法,更新视图。 document.body.appendChild(base); };
上面的代码要注意两点:
1.模型photoModel将render方法作为一个订阅者添加进去,以便在model改变时,可以通过观察者模式执行render方法,触发viwe的更新。
2.当用户点击视图时,视图没有责任去了解下一步要做什么,它依赖于控制器photoController来为它做这个决定。
由于上面我们使用到了underscore库的模板函数,因此我们来了解下模板这个东西。
我们web开发人员都知道,手工创建大量的html标记,并通过字符串拼接是非常不好的性能实践。javascript模板解决方案就是解决这个问题的。
视图就是由html结构和后台返回的数据(model)拼接出来,显示在浏览器中的。模板的概念就是:我们可以提前把html结构写出来,然后在这个结构中添加一些标记,这些标记的地方是用json数据来填充的,这种结构,我们就可以称作为模板。模板的好处是什么?我们只需要关注模板和model(模型),就可以构建出正确的html字符串(视图view),显示在浏览器中。而不用去自己手工组装。当然这里的model,我们要转换成json数据格式才行。
举个例子:
使用handlebars.js
<li class="photo"> <h2>{{caption}}<h2> //{{}}就是标记
<img class="source" src="{{src}}"/> </li>
使用underscore.js
<li class="photo"> <h2><%= caption %><h2> // <%= %> 就是标记 <img class="source" src="<%= src %>"/> </li>
Controller(控制器)
控制器是model和view之间的中介,当用户操作视图时,它通常负责更新model。
在大多数javascript的mvc框架中,controller的角色比较弱。因为mvc模式最初是从服务器端提出来的,所以不太适合应用在javascript中。
Backbone包含model和view,但它实际上并没有真正的controller。其view和路由(router)的功能与controller类似,但它们不是controller。
所有backbone的mvc模式跟经典的mvc模式(服务端提出的mvc)是不一样的,而且可以这样说,前端的mvc模式或者说javascript的mvc模式跟经典mvc模式是有区别的。
在Backbone中,Backbone.View和Backbone.Router一起承担Controller的责任。Backbone之前的版本确实有Backbone.Controller,但是这个组件的命名在它使用的上下文中没有意义,于是改名为Router。
Router拥有更多一点的Controller的责任。
举个例子:
var PhotoRouter = Backbone.Router.extend({ routes:{"photos/:id": "route"}, //浏览器上的网址URL字符串#后面的字符串改变时,比如,从chaojidan变成了chaojidan1时,就会执行route方法,并传入id="chaojidan1" route:function(id){ var item = photoCollection.get(id); //通过id获取特定的模型 var view = new PhotoView({model:item}); //通过此模型创建出视图 $(".content").html(view.render().el); //把视图显示在浏览器中 } });
总而言之,controller管理应用程序中model和view之间的逻辑和协调。
MVC模式最大的好处就是解耦model和view的代码,这意味着开发人员能够更直接的编写业务逻辑。
这种模块性可以让负责核心逻辑的开发人员和负责用户界面的开发人员同时工作。
MVC模式依赖于观察者模式,当模型(目标)被改变时,它会通知视图(观察者)更新。这种关系,也促进了多个view被附加到同一个model,即多个观察者与一个目标的关系。
加油!