【干货理解】理解javascript中实现MVC的原理
理解javascript中的MVC
MVC模式是软件工程中一种软件架构模式,一般把软件模式分为三部分,模型(Model)+视图(View)+控制器(Controller);
模型:模型用于封装与应用程序的业务逻辑相关的数据以及对数据处理的方法。模型有对数据直接访问的权利。模型不依赖 "视图" 和 "控制器", 也就是说 模型它不关心页面如何显示及如何被操作.
视图:视图层最主要的是监听模型层上的数据改变,并且实时的更新html页面。当然也包括一些事件的注册或者ajax请求操作(发布事件),都是放在视图层来完成。
控制器:控制器接收用户的操作,最主要是订阅视图层的事件,然后调用模型或视图去完成用户的操作;比如:当页面上触发一个事件,控制器不输出任何东西及对页面做任何处理; 它只是接收请求并决定调用模型中的那个方法去处理请求, 然后再确定调用那个视图中的方法来显示返回的数据。
下面我们来实现一个简单的下拉框控件,我们可以对它进行增删操作;如下图所示:

代码如下:
/*
模型用于封装与应用程序的业务逻辑相关的数据以及对数据处理的方法。模型有对数据直接访问的权利。
模型不依赖 "视图" 和 "控制器", 也就是说 模型它不关心页面如何显示及如何被操作.
*/
function Mode(elems) {
// 所有元素
this._elems = elems; // 被选中元素的索引
this._selectedIndex = -1; // 增加一项
this.itemAdd = new Event(this); // 删除一项
this.itemRemoved = new Event(this); this.selectedIndexChanged = new Event(this);
} Mode.prototype = { constructor: 'Mode', // 获取所有的项
getItems: function(){
return [].concat(this._elems);
},
// 增加一项
addItem: function(elem) {
this._elems.push(elem);
this.itemAdd.notify({elem:elem});
},
// 删除一项
removeItem: function(index) {
var item = this._elems[index];
this._elems.splice(index,1);
this.itemRemoved.notify({elem:item}); if(index === this._selectedIndex) {
this.setSelectedIndex(-1);
}
},
getSelectedIndex: function(){
return this._selectedIndex;
},
setSelectedIndex: function(index){
var previousIndex = this._selectedIndex;
this._selectedIndex = index;
this.selectedIndexChanged.notify({previous : previousIndex});
}
};
/*
下面是观察者模式类,它又叫发布---订阅模式;它定义了对象间的一种一对多的关系,
让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。
*/
function Event(observer) {
this._observer = observer;
this._listeners = [];
}
Event.prototype = {
constaructor: 'Event',
attach : function(listeners) {
this._listeners.push(listeners);
},
notify: function(objs){
for(var i = 0,ilen = this._listeners.length; i < ilen; i+=1) {
this._listeners[i](this._observer,objs);
}
}
}; /*
* 视图显示模型数据,并触发UI事件。
*/
function View(model,elements){
this._model = model;
this._elements = elements; this.listModified = new Event(this);
this.addButtonClicked = new Event(this);
this.delButtonClicked = new Event(this);
var that = this; // 绑定模型监听器
this._model.itemAdd.attach(function(){
that.rebuildList();
});
this._model.itemRemoved.attach(function(){
that.rebuildList();
}); // 将监听器绑定到HTML控件上
this._elements.list.change(function(e){
that.listModified.notify({index: e.target.selectedIndex});
});
// 添加按钮绑定事件
this._elements.addButton.click(function(e){
that.addButtonClicked.notify();
});
// 删除按钮绑定事件
this._elements.delButton.click(function(e){
that.delButtonClicked.notify();
});
}
View.prototype = {
constructor: 'View',
show: function(){
this.rebuildList();
},
rebuildList: function(){
var list = this._elements.list,
items,
key;
list.html("");
items = this._model.getItems();
for(key in items) {
if(items.hasOwnProperty(key)) {
list.append('<option value="'+items[key]+'">' +items[key]+ '</option>');
}
}
this._model.setSelectedIndex(-1);
}
};
/*
控制器响应用户操作,调用模型上的变化函数
负责转发请求,对请求进行处理
*/
function Controller(model,view) {
this._model = model;
this._view = view;
var that = this; this._view.listModified.attach(function(sender,args){
that.updateSelected(args.index);
});
this._view.addButtonClicked.attach(function(){
that.addItem();
});
this._view.delButtonClicked.attach(function(){
that.delItem();
});
}
Controller.prototype = {
constructor: 'Controller', addItem: function(){
var item = window.prompt('Add item:', '');
if (item) {
this._model.addItem(item);
}
}, delItem: function(){
var index = this._model.getSelectedIndex();
if(index !== -1) {
this._model.removeItem(index);
}
}, updateSelected: function(index){
this._model.setSelectedIndex(index);
}
};
HTML代码如下:
<select id="list" size="10" style="width: 10rem"></select><br/>
<button id="plusBtn"> + </button>
<button id="minusBtn"> - </button>
页面初始化代码如下:
$(function () {
var model = new Mode(['PHP', 'JavaScript']),
view = new View(model, {
'list' : $('#list'),
'addButton' : $('#plusBtn'),
'delButton' : $('#minusBtn')
}),
controller = new Controller(model, view);
view.show();
});
代码分析如下:
先分下下 我们是要实现什么样的功能; 基本功能有:一个下拉框,通过用户输入的操作来实现用户增加一项及用户选中一项后删除一项的功能;
当然也添加了用户切换到那一项的事件;
比如我们现在来增加一条数据的时候,在视图层上添加监听事件,如下代码:
// 添加按钮绑定事件
this._elements.addButton.click(function(e){
that.addButtonClicked.notify();
});
然后调用观察者类Event中的方法notify(发布一个事件) that.addButtonClicked.notify();大家都知道,观察者模式又叫发布-订阅模式,
让多个观察者对象同时监听某一个主题对象,当某一个主题对象发生改变的时候,所有依赖它的对象都会得到通知;
因此在控制层(Controller)我们可以使用如下代码对发布者进行监听操作:
this._view.addButtonClicked.attach(function(){
that.addItem();
});
之后调用自身的方法addItem();代码如下:
addItem: function(){
var item = window.prompt('Add item:', '');
if (item) {
this._model.addItem(item);
}
}
调用模型层(model)的方法addItem();把一条数据插入到select框里面去;model(模型层)的addItem()方法代码如下:
// 增加一项
addItem: function(elem) {
this._elems.push(elem);
this.itemAdd.notify({elem:elem});
},
如上代码 增加一项后,通过 this.itemAdd 发布一个消息,然后在视图层(View)上通过如下代码来监听这个消息;代码如下:
// 绑定模型监听器
this._model.itemAdd.attach(function(){
that.rebuildList();
});
最后监听到模型上(Model)的数据发生改变后,及时调用自身的方法rebuildList()去更新页面上的数据;
模型层(Model)最主要做业务数据封装操作。视图层(View)主要发布事件操作及监听模型层上的数据,如果模型层上有数据改变的时候,及时更新页面操作,
最后显示给页面上来,控制层(Controller)主要监听视图层(View)的事件,调用模型层(Model)的方法来更新模型上的数据,模型层数据更新后,会发布
一条消息出去,最后视图层(View)通过监听模型层(Model)的数据变化,来更新页面的显示; 如上是MVC的基本流程。
MVC的优点:
1. 耦合性低:视图层和业务层分离了,如果页面上显示改变的话,直接在视图层更改即可,不用动模型层和控制层上的代码;也就是视图层 与 模型层和控制层
已经分离了;所以很容易改变应用层的数据层和业务规则。
2. 可维护性:分离视图层和业务逻辑层也使得WEB应用更易于维护和修改。
MVC的缺点:
个人觉得适合于大型项目,对于中小型项目并不适合,因为要实现一个简单的增删改操作,只需要一点点JS代码,但是MVC模式代码量明显增加了。
对于学习成本也就提高了,当然如果使用一些封装好的MVC库或者框架就好了。
【干货理解】理解javascript中实现MVC的原理的更多相关文章
- JavaScript中实现DI的原理(二)
JavaScript中实现DI的原理 在JavaScript中实现DI,看起来难,实际上原理很简单,它的核心技术是Function对象的toString().我们都知道,对一个函数对象执行toStri ...
- JavaScript中this的工作原理以及注意事项
在JavaScript中,this 的概念比较复杂.除了在面向对象编程中,this 还是随处可用的.这篇文章介绍了this 的工作原理,它会造成什么样的问题以及this 的相关例子. 要根据this ...
- javaScript中闭包的工作原理
一.什么是闭包? 官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.相信很少有人能直接看懂这句话,因为他描述的太学术.其实这句话 ...
- 详解javascript中this的工作原理
在 JavaScript 中 this 常常指向方法调用的对象,但有些时候并不是这样的,本文将详细解读在不同的情况下 this 的指向. 一.指向 window: 在全局中使用 this,它将会指向全 ...
- javascript中new操作符的原理
javascript中的new是一个语法糖,对于学过c++,java 和c#等面向对象语言的人来说,以为js里面是有类和对象的区别的,实现上js并没有类,一切皆对象,比java还来的彻底 new的过程 ...
- 我所理解的javascript中函数的作用域和作用域链
本文为原创,转载请注明出处: cnzt 文章:cnzt-p 写在前面 一周木有更新了,今天终于攻克了自行车难关,非常开心,特意来一更~ (那些捂嘴偷笑的人我看到你们了快把嘴闭上我会假装没看 ...
- 30行代码实现Javascript中的MVC
从09年左右开始,MVC逐渐在前端领域大放异彩,并终于在刚刚过去的2015年随着React Native的推出而迎来大爆发:AngularJS.EmberJS.Backbone.ReactJS.Rio ...
- JavaScript中的原型继承原理
在JavaScript当中,对象A如果要继承对象B的属性和方法,那么只要将对象B放到对象A的原型链上即可.而某个对象的原型链,就是由该对象开始,通过__proto__属性连接起来的一串对象.__pro ...
- JavaScript中的作用域链原理
执行环境 作用域链的形成与执行环境(Execution Environment)相关,在JavaScript当中,产生执行环境有如下3中情形: 1 进入全局环境 2 调用eval函数 3 调用func ...
随机推荐
- 【bzoj2705】 SDOI2012—Longge的问题
http://www.lydsy.com/JudgeOnline/problem.php?id=2705 (题目链接) 题意 给定一个整数N,你需要求出∑gcd(i, N)(1<=i <= ...
- 【poj1741】 Tree
http://poj.org/problem?id=1741 (题目链接) 题意 给出一个n个节点的带权树,求树上距离不超过K的所有点对的个数. solution 点分治裸题.所谓的点分治,就是对于 ...
- DayuCMS 1.525 /include/global.func.php Foreground Arbitrary Code Execution
catalog . 漏洞描述 . 漏洞触发条件 . 漏洞影响范围 . 漏洞代码分析 . 防御方法 . 攻防思考 1. 漏洞描述 Relevant Link: http://joychou.org/in ...
- (原)String、StringBuilder、StringBuffer作为形参
今天在刷一道算法题时,突然遇到StringBuilder作为形参和String作为形参时,最终得出来的结果不同.故尝试了几个demo看看它们之间的区别. 当String类型作为参数时, public ...
- Django 自带的ORM增删改查
通过Django来对数据库进行增删改查 1 首先创建类,在app应用程序里面的model模块里面创建类,写好数据库信息,方便我们待会初始化: 2 创建在django项目里面的settings里面添加 ...
- 网站缓存数据到tomcat服务器
通过缓存使相同的数据不用重复加载,降低数据库的访问 public class CacheFilter implements Filter { //实例变量[每线程共享] private Map< ...
- 实现BPEL4WS演示:教程
http://www.ibm.com/developerworks/cn/education/webservices/ws-bpelws/bpel_tutorial_cn.html 开始 什么是Bus ...
- 修改nginx的访问目录以及遇到的403错误修改总结
对于这个问题困扰了我好几天,前篇文章介绍了图片服务器的使用,但是两个服务器如何进行通话访问呢,即如何通过nginx来访问ftp服务器上的资源文件呢,这里面需要修改nginx的配置文件(vi /usr/ ...
- Ajax Post 类实例
以前总是ajax请求是这样的 data:"a=1&b=2&c=3..." 而Controller也总是这样的 Action(int a,int b,int c) 很 ...
- struts2权威指南学习笔记:struts2引入自定义库
问题: 在jsp页面中添加了s:property标签,然而在页面始终未展示 解决: 经过搜索学习,发现只要添加语句 1 <%@ taglib prefix="s" uri=& ...