【干货理解】理解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 ...
随机推荐
- Jenkins配置MSBuild编译.net4.6的项目
经过测试,如果用原始的msbuild,会出现语法无法识别的问题,"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe&qu ...
- VS2010生成安装包
项目的第一个版本出来了,要做个安装包,之前没有做过,网上看看贴,写了一个,总结下,根据本项目的需要,没有写的太复杂,可能还不是很完善,仅作参考. 首先在打开 VS2010 > 文件 & ...
- AngularJs angular.equals
angular.equals 对比两个对象/值是否相等.支持值类型.正则表达式.数组和对象. 如果下列至少有一个是正确的,则将两个对象/值视为相等. 两个对象/值能通过===比较. 两个对象/值是同一 ...
- CF 268E Playlist(贪心)
题目链接: 传送门 Playlist time limit per test:1 second memory limit per test:256 megabytes Description ...
- Appium运行时,error: Logcat capture failed: spawn ENOENT的解决办法
目前发现有以下两种可能: 一:查看环境变量是否配置成功. ANDROIDSDK D:\my_2_softwares\JAVA\adt-bundle-windows-x86-20140702\sdkPA ...
- ARPSpoofing教程(二) - 获取网络设备中的详细地址信息
WinPcap中文API http://www.ferrisxu.com/WinPcap/html/index.html 1: #include"pcap.h" 2: #incl ...
- hdu 2010 - 水仙花数
题意: 数学上有个水仙花数,他是这样定义的:"水仙花数"是指一个三位数,它的各位数字的立方和等于其本身,比如:153=1^3+5^3+3^3.现在要求输出所有在m和n范围内的水仙花 ...
- Mysql学习笔记(八)由触发器回顾外键约束中的级联选项
近些天都没有写博客.在学习mysql的知识,通过学习和练习,也熟悉了mysql的函数.触发器.视图和存储过程.并且在实际的开发过程中也应用了一小部分.效果还是十分理想的. 今天晚上在学习触发器模仿in ...
- 我所了解的meta
https://github.com/hoosin/mobile-web-favorites 总况 meta 标签分两大部分:HTTP 标题信息(http-equiv)和页面描述信息(name). h ...
- 介绍ping中的TTL是什么意思
ping是icmp报文的一种应用.用来测试网络中各设备的连通性.在这几天的实验课上,我又用到了这个非常常用的命令,但是这次我发现了一些以前没有太注意的地方,那就是我在Ping不同的地址时所返回的TTL ...