MVC是什么?

MVC是一种架构模式,它将应用抽象为3个部分:模型(数据)、视图、控制器(分发器)

本文将用一个经典的例子todoList来展开

一个事件发生的过程(通信单向流动):

1、用户在视图V上与应用程序交互

2、控制器C触发相应的事件,要求模型M改变状态(读写数据)

3、模型M将数据发送到视图V,更新数据,展现给用户

在js的传统开发模式中,大多基于事件驱动的:

1、hash驱动

2、DOM事件,用来驱动视图

3、模型事件(业务模型事件和数据模型事件),用来驱动模型和模型结合

所以js中的MVC的特点是:单向流动、事件驱动

一)模型

模型存放着应用的所有数据对象(业务数据、数据校验、增删改查),比如,例子todoList中的store模型,存放每一条记录与之有关的逻辑

数据时面向对象的,当控制器请求模型读写数据时,模型就将数据包装成模型实例。任何定义在这个数据模型上的函数或逻辑都可以直接被调用。在本文的例子中采用localStorage也是类似道理的。存储的Todos可以随时被调用

模型不关心,不包含视图和控制器的逻辑。它们应该是相互解耦的。这里提一点,模型与视图的耦合,显然是违反MVC架构原则,但往往我们有时候却因为业务关系而无法完全解耦

模型表现了领域特定的数据,当一个模型有所改变的时候,它会通知它的观察者

二)视图

视图是呈现给用户的,是用户交互的第一入口。它定义配置、管理者每个页面相应的模板与组件,它表现为一个模型的当前状态,视图通过观察者模式监视模型,以获得最新的数据,来呈现最新的页面。

所以,页面首次加载时,往往是从接受模型的数据开始

三)控制器

控制器(分发器),是模型和视图之间的桥梁,集中式地配置和管理事件分发、模型分发、视图分发,还用来权限控制、异常处理等。我们的应用中往往是有多个控制器的

页面加载完成后,控制器会监听视图的用户交互(按钮点击或表单提交),一旦用户发生交互时,控制器做出视图的选择,触发控制器的事件处理机制,去派发新的事件,通知模型更新数据

Demo-todoList


最后这里是一个用原生js写的todoList,这个demo做的很简陋,点击输入文字点击确定就添加,删除是直接点击该行信息

单独分离开来举例子不好讲,所以在代码中进行注释。首先简单理下下边代码的思路:

1、V层定义配置了一个显示数据的字符串模板,同时定义一个订阅者的回调函数render()用于页面更新数据

2、C层监听用户的添加与删除操作,添加是add()函数,他执行了回调函数render,同时向M层写入数据,通知M层改变,删除操作同理

3、M层是本地存储localStorage,模拟一个存储数据对象的后台模型

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>todo</title>
</head>
<body>
<header>
<h3>待定事项</h3>
</header>
<main>
<ul id="todoList"></ul>
<input type="text" id="content">
<button id="confirm">确认</button>
</main>
<script>
(function(){
const ADD_KEY='_todoList_'
const Utils={
//模拟Modal(实体模型)
store(key,data)
if(arguments.length>){
return localStorage.setItem(key,JSON.stringify(data));
}
else{
let storeData=localStorage.getItem(key);
return (storeData &&JSON.parse(storeData))||[];//这里一定要设置初始值为[]
}
}
}
class Todo{
constructor(id,text=""){
this.id=id;
this.text=text
}
}
let App={
init(){
//this.todos为一个存储json对象的数组,是一个实例化的数据对象,可任意调用
this.todos=Utils.store(ADD_KEY)
this.findDom()
this.bindEvent()
this.render()//初始化渲染
},
findDom(){
this.contentBox=document.querySelector("#content")
this.confirm=document.querySelector("#confirm")
this.todoList=document.querySelector("#todoList")
this.todoListItem=document.getElementByTagName("li")
},
//模拟Controller(业务逻辑层)
bindEvent(){
this.confirm.addEventListener('click',()=>{
//要求模型M改变状态,add()函数是写入数据操作
this.add()
},false)
this.todoList.addEventListener('click',(item)=>{//时间委托,优化性能
this.remove(item)
},false)
},
//这里勉强抽象成一个视图吧
view(){
let fragment=document.createDocumentFragment()//减少回流次数
fragment=''
for(let i=;i<this.todos.length;i++){ //一次性DOM节点生成
//这里使用拼接字符串代替视图的模板,
//模板是用一种声明的方式指定部分甚至所有的视图对象
fragment +='<li>&{this.todos[i].text}</li>
}
this.todoList.innerHTML=fragment
},
//render()函数作为一个订阅者的回调函数,数据的变化会反馈到模型store
//换句话说:视图通过观察者模式,观察模型store,当模型发生改变,触发视图更新
render(){
this.view()
Utils.store(ADD_KEY,this.todos)
},
getItemIndex(item){
let itemIndex
if (item.target.tagName.toLowerCase()==='li'){
let arr=Array.prototype.slice.call(this.todoListItem)
let index=arr.indexOf(item.target)
return itemIndex=index
}
},
add(e){
let id=Number(new Date())
let text=this.contentBox.value
let addTodo=new Todo(id,text)
this.todos.unshift(addTodo)//模型发生改变
this.render()//当模型发生改变,触发视图更新
},
remove(item){
let index=this.getItemIndex(item)
this.todos.splice(index,)
this.render()
}
}
App.init()
})()
</script>
</body>
</html>

随着界面和逻辑的复杂,用js或者jq去控制DOM是不现实的。上边例子只是用原生js模拟MVC的思想实现过程。真正地项目往往会依赖一些封装好的优秀库进行高效开发

MVC模式的优点

MVC编程把所有精力放在数据处理,尽可能减少对网页元素的处理。对于有一定数量功能的网页,MVC模式下强制规范代码,简化,减少重复代码,使代码易于扩充

MVC模式的弊端

1、清晰的构架以代码的复杂性为代价,对小项目反而降低开发效率

2、控制层和视图层耦合,导致没有真正分离和重用

3、在同一业务逻辑下,如果存在多种视图呈现,需要视图定义配置多个模板引擎、数据解析,多次处理数据与页面更新。代码就充满了各种选择器与事件回调,随着业务的膨胀,变得难以维护

总结:其实,现在MVC在前端用得比较少了,因为它的局限性,催生了MVVM模式的流行与广泛使用

浅谈js中的MVC的更多相关文章

  1. 浅谈JS中的闭包

    浅谈JS中的闭包 在介绍闭包之前,我先介绍点JS的基础知识,下面的基础知识会充分的帮助你理解闭包.那么接下来先看下变量的作用域. 变量的作用域 变量共有两种,一种为全局变量,一种为局部变量.那么全局变 ...

  2. 浅谈JS中的!=、== 、!==、===的用法和区别 JS中Null与Undefined的区别 读取XML文件 获取路径的方式 C#中Cookie,Session,Application的用法与区别? c#反射 抽象工厂

    浅谈JS中的!=.== .!==.===的用法和区别   var num = 1;     var str = '1';     var test = 1;     test == num  //tr ...

  3. 浅谈JS中 var let const 变量声明

    浅谈JS中 var let const 变量声明 用var来声明变量会出现的问题: 1. 允许重复的变量声明:导致数据被覆盖 2. 变量提升:怪异的数据访问.闭包问题 3. 全局变量挂载到全局对象:全 ...

  4. 由项目浅谈JS中MVVM模式

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.    背景 最近项目原因使用了durandal.js和knock ...

  5. js架构设计模式——由项目浅谈JS中MVVM模式

    1.    背景 最近项目原因使用了durandal.js和knockout.js,颇有受益.决定写一个比较浅显的总结. 之前一直在用SpringMVC框架写后台,前台是用JSP+JS+标签库,算是很 ...

  6. 浅谈js中的数据类型,使用typeof获取js数据类型

    JS中的数据类型 1):Undefined——值未定义 注:Undefined类型只有一个值,即特色的undefined.在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined ...

  7. 浅谈js中的浅拷贝和深拷贝

    在js中如何把一个对象里的属性和方法复制给另一个对象呢? 下面举一个例子来说明: var person={name:'chen',age:18}; var son={sex:'男'}; functio ...

  8. 浅谈JS中的高级函数

    在JavaScript中,函数的功能十分强大.它们是第一类对象,也可以作为另一个对象的方法,还可以作为参数传入另一个函数,不仅如此,还能被一个函数返回!可以说,在JS中,函数无处不在,无所不能,堪比孙 ...

  9. 浅谈js中null和undefined的区别

    在JS中,null和undefined是经常让人摸不着头脑的东西,尤其是在数据初始化以及处理的过程中,经常稍微不注意,就会让页面在渲染时出现报错,下面来细说下,这两者之间的区别: null 表示一个对 ...

随机推荐

  1. ionic2 jpush

    ionic2 为ionic2调用极光插件提供符合angular2及TS的调用方式 install 先安装官方的cordova插件 $ cordova plugin add jpush-phonegap ...

  2. Web系统从Oracle迁移至MySQL

    前两天领导给了个活,数据库迁移,原来的系统是用的Oracle数据库,现在要改成MySql,当时没多想就接下来了,原来的系统用的框架式SSI,于是大概想了下需要作调整无非以下几点 第一 数据库迁移 第二 ...

  3. BZOJ 2813: 奇妙的Fibonacci

    2813: 奇妙的Fibonacci Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 497  Solved: 134[Submit][Status][ ...

  4. 【字符集及字符编码】UTF-8、UTF-16和UTF-32

    UTF-32 用 4 个字节存储每一个字符,以保证能把 UCS 完全表达出来.但实际上 UCS 的字符数量根本不需要用 32 位表示,UTF-32 极大地浪费了空间.另外,由于组合字符的存在,定长表示 ...

  5. 7天学习opengl入门

    http://blog.csdn.net/slience_perseverance/article/details/8096233 10月13号下午3:00队长给我开了一个会,10.14号开始学习op ...

  6. 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---33

    以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下:

  7. Python Challenge 第十二关

    这一关依旧只有一张图,右键源代码也没有任何注释,也用PIL处理过那张图但没任何头绪,没办法只有上网搜答案. 别人的博客里说,源代码里面图片的名字是 evil1.jpg,那肯定会有 evil2.jpg. ...

  8. (11)centos之vim使用

    ZZ 保存并退出 :x 保存并退出 :q 不保存退出

  9. Codeforces 147B Smile House(DP预处理 + 倍增)

    题目链接  Smile House 题意  给定一个$n$个点的有向图,求一个点数最少的环,使得边权之和$>0$,这里的环可以重复经过点和边.   满足  $n <= 300$ 首先答案肯 ...

  10. HDU 5242 Game(树上贪心)

    题目链接 Game 题目的意思很简单, 就是要找一棵树权值最大等等前K条链. 在本题中,走的次数等于min(叶子结点个数,k) tree[i].sum意为从i号结点出发走到某个叶子结点能得到的最大总价 ...