理解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的原理的更多相关文章

  1. JavaScript中实现DI的原理(二)

    JavaScript中实现DI的原理 在JavaScript中实现DI,看起来难,实际上原理很简单,它的核心技术是Function对象的toString().我们都知道,对一个函数对象执行toStri ...

  2. JavaScript中this的工作原理以及注意事项

    在JavaScript中,this 的概念比较复杂.除了在面向对象编程中,this 还是随处可用的.这篇文章介绍了this 的工作原理,它会造成什么样的问题以及this 的相关例子. 要根据this  ...

  3. javaScript中闭包的工作原理

    一.什么是闭包? 官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.相信很少有人能直接看懂这句话,因为他描述的太学术.其实这句话 ...

  4. 详解javascript中this的工作原理

    在 JavaScript 中 this 常常指向方法调用的对象,但有些时候并不是这样的,本文将详细解读在不同的情况下 this 的指向. 一.指向 window: 在全局中使用 this,它将会指向全 ...

  5. javascript中new操作符的原理

    javascript中的new是一个语法糖,对于学过c++,java 和c#等面向对象语言的人来说,以为js里面是有类和对象的区别的,实现上js并没有类,一切皆对象,比java还来的彻底 new的过程 ...

  6. 我所理解的javascript中函数的作用域和作用域链

    本文为原创,转载请注明出处: cnzt       文章:cnzt-p 写在前面 一周木有更新了,今天终于攻克了自行车难关,非常开心,特意来一更~ (那些捂嘴偷笑的人我看到你们了快把嘴闭上我会假装没看 ...

  7. 30行代码实现Javascript中的MVC

    从09年左右开始,MVC逐渐在前端领域大放异彩,并终于在刚刚过去的2015年随着React Native的推出而迎来大爆发:AngularJS.EmberJS.Backbone.ReactJS.Rio ...

  8. JavaScript中的原型继承原理

    在JavaScript当中,对象A如果要继承对象B的属性和方法,那么只要将对象B放到对象A的原型链上即可.而某个对象的原型链,就是由该对象开始,通过__proto__属性连接起来的一串对象.__pro ...

  9. JavaScript中的作用域链原理

    执行环境 作用域链的形成与执行环境(Execution Environment)相关,在JavaScript当中,产生执行环境有如下3中情形: 1 进入全局环境 2 调用eval函数 3 调用func ...

随机推荐

  1. bzoj3669[Noi2014]魔法森林

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  2. rfc2616 HTTP Protocl Analysis

    catalog . Introduction . Protocol Parameters . HTTP Message . Request . Response . HTTP Method.Conte ...

  3. NYOJ 16 矩形嵌套(经典动态规划)

    传送门 Description 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于 ...

  4. CF 444C DZY Loves Physics(图论结论题)

    题目链接: 传送门 DZY Loves Chemistry time limit per test1 second     memory limit per test256 megabytes Des ...

  5. 旅图beta版 asp.net web api 单元测试

    旅图 beta版 asp.net web api 单元测试 测试接口:http://120.27.7.115:1010/Help 测试目的 对每个接口单元进行测试,保证每个接口的可靠性. 单元描述 注 ...

  6. Linux下串口编制【转】

    串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用.常用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统.调制解调 ...

  7. Win7系统开放C盘下文件夹Everyone权限

    安装软件时遇到这样的情况:我就是管理员权限啊,怎么会安装有问题呢? 后来知道,用户名即使分配了你是管理员权限,有些文件还是有限制的(特别是C盘) 昨天遇到一个问题,有个文件夹里的隐藏文件就是无法显示, ...

  8. 在JavaScript中,arguments是对象的一个特殊属性。

    arguments对象 function函数的内置参数的"数组"/"集合":同时arguments对象就像数组,但是它却不是数组. 常用属性: 1.length ...

  9. 写Action的三种方法

    Action类似于servlet,在用户对浏览器输入url访问的时候充当控制器的角色.它在访问时产生,执行execute()之后就销毁了. 写Action是代理事务,它实现的三种方式是: (1)POJ ...

  10. oc必须知道的知识点

    id数据类型 1.通用的指针类型 2.没有*号 3.使用id类型时,不能给对象的属性或成员变量进行赋值 4.可以对其发送任何(存在的)消息   import与@class的区别 1.import会包含 ...