1. MVC背景
MVC是一种架构设计模式,它通过关注点分离鼓励改进应用程序组织。在过去,MVC被大量用于构建桌面和服务器端应用程序,如今Web应用程序的开发已经越来越向传统应用软件开发靠拢,Web和应用之间的界限也进一步模糊。传统编程语言中的设计模式也在慢慢地融入Web前端开发。
2. MVC是什么
| 简写 | 缩写 | 通俗理解 | 描述 |
|---|---|---|---|
| M | 模型(Model) | 数据保存 | 模型model用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法,会有一个或多个视图监听此模型。一旦模型的数据发生变化,模型将通知有关的视图。 |
| V | 视图(View) | 用户界面 | 视图view是它在屏幕上的表示,描绘的是model的当前状态。当模型的数据发生变化,视图相应地得到刷新自己的机会。 |
| C | 控制器(Controller) | 业务逻辑 | 控制器controller定义用户界面对用户输入的响应方式,起到不同层面间的组织作用,用于控制应用程序的流程,它处理用户的行为和数据model上的改变。 |
传统意义上的MVC各个部分之间的通信是单向的
-
View 传送指令到 Controller
-
Controller 完成业务逻辑后,要求 Model 改变状态
-
Model 将新的数据发送到 View,用户得到反馈
3. MVC简单举例说明
- Model
Model = {
data: { 程序需要操作的数据或信息 },
create: { 增数据 },
delete: { 删数据 },
update(data) {
Object.assign(m.data, data) //使用新数据替换旧数据
eventBus.trigger('m:upate') // eventBus触发'm:update'信息, 通知View刷新
},
get:{ 获取数据 }
}
- View
View = {
el: 需要渲染的元素,
html: `<h1>这里是要渲染的内容</h1>`
init(){
v.el: 需要渲染的元素
},
render(){ 渲染页面 }
}
- Controller
Controller = {
init(){
v.init() // View初始化
v.render() // 第一次渲染
c.autoBindEvents() // 自动的事件绑定
eventBus.on('m:update', () => { v.render() }) // 当eventBus触发'm:update'时View刷新
},
events:{ 事件以哈希表方式记录 },
method() {
data = 改变后的新数据
m.update(data)
},
autoBindEvents() { 自动绑定事件 }
}EventBus
4. EventBus的API
DOM 的事件机制就是发布订阅模式最常见的实现,这大概是前端最常用的编程模型了,监听某事件,当该事件发生时,监听该事件的监听函数被调用。eventBus就是实现发布订阅模式的一种方法。
其实jquery和vue构造出来的对象都有监听事件的方法,我们只需要构造一个对象,然后调用他的on 和 trigger方法就可以实现组件之间的通信.
下面介绍几个vue常用的事件api及其内部实现
1. $on 事件的订阅
$on(eventName,callback)
//参数1:事件名称 参数2:事件函数
//判断当前事件名称是否存在,如果不存在则创建一个key值为事件名称
//value为一个数组 将callback push到数组中
const eventList = {};
const $on = (eventName,callback)=>{
if(!eventList[eventName]){
eventList[eventName] = [];
}
eventList[eventName].push(callback)
}
2. $off 事件的解绑
$off(eventName,[callback])
//参数1:事件名称 参数2:[事件函数]
//判断当前事件名称是否存在,如果存在继续判断第二个参数是否存在,如果存在则找到相//对应的下标 然后将函数在数组中移除
//如果不存在则将整个数组清空
const eventList = {};
const $off = (eventName,callback)=>{
if(eventList[eventName]){
if(callback){
let index = eventList[eventName].indexOf(callback);
eventList[eventName].splice(index,1)
}
}else{
eventList[eventName].length = 0;
}
}
export default = {
$on,
$emit,
$off
}
3. $emit 事件的触发
$emit(eventName,[params])
//参数1:事件名称 参数2:[需要传递的参数]
//判断当前事件的名称是否存在,如果存在则遍历数组,得到所有的函数,
//并执行。然后将params当做实参传递到函数中去
const eventList = {};
const $emit = (eventName,params)=>{
if(eventList[eventName]){
let arr = eventList[eventName];
arr.map((cb)=>{
cb(params)
})
}
}
5. 表驱动编程
新手写代码逻辑时常常会写许多的条件判断,会出现一大串的if...else...,导致代码看起来十分凌乱,这里简单介绍一下表驱动编程的思想。
例如,我们要写一个查询年龄的函数:
function age(name){
if(name==="小明"){
console.log("年龄是"+10)
}else if(name==="小白"){
console.log("年龄是"+14)
}else if(){
}
//....等等
}
可以看出,这里有多少人我们就得写多少个if...else...语句,这样我们的代码量是线性增长的,如果我们用一个哈希表来记录这些映射关系的话,结果如下:
const list={
"小明":10,
"小白":14,
//等等...
}
function age2(name){
if(name in list){
console.log(name+"的年龄是"+list[name])
}else{
console.log("查无此人")
}
}
如此一来,我们的数据就和实现逻辑的代码分离了,函数主体只是去表中查找然后输出结果,这就是表驱动编程的基本思想。可以减少无用重复的工作。
6. 如何理解模块化
所谓模块化其实就是封装,把一些实现特定功能的常用的、易用的代码写在一个函数或者一个文件中,以便重复调用。
模块化可以把细节隐藏起来,只提供使用的
API接口,与其他模块之间互不影响,每个模块都独立的实现一些特定的功能。