一、MVC中的M、V、C的含义
MVC是三个单词的首字母缩写,它们是Model(模型)、View(视图)和Controller(控制)。
-
最上面的一层,是直接面向最终用户的"视图层"(View)。它是提供给用户的操作界面,是程序的外壳。
-
最底下的一层,是核心的"数据层"(Model),也就是程序需要操作的数据或信息。
-
中间的一层,就是"控制层"(Controller),它负责根据用户从"视图层"输入的指令,选取"数据层"中的数据,然后对其进行相应的操作,产生最终结果。
MVC的用途:
谓的面条式代码:一团糟、代码重复率高,为此就有人发明了MVC框架。它的用途就是通过数据处理、事件绑定、重新渲染等模块化方式来把这一团糟糕的代码进行逐步简化成万金油的代码。
现给出需求,给一个初始数字,然后用户可以进行+、-、*、/的相关操作,来看下MVC三个对象在代码中的具体实现
1. M对象:保留所有数据,且对数据暴露出增删改查四个API,用于后期操作数据。
const m = {
data: {数据A},
create() {},
delete() {},
update(data) {
Object.assign(m.data,data)//用新数据替换旧数据
eventBus.trigger('m:update')//eventBus触发'm:update'信息,通知View刷新界面
},
get() {数据A}
}
2. V对象:负责渲染到页面,所以我们将之前的inedx.html放到了V上。
const v = {
el: 需要刷新的元素,
html: `
body里面的内容
`,
init(container) {
v.el = $(container)
},
render(n) {刷新页面}
}
3. C对象:控制层,根据视图层的输入命令,选取数据层中的进行一系列操作。
const c = {
init(container) {
v.init()//初始化View
v.render()//第一次渲染页面
c.autoBindEvents()//自动的事件绑定
eventBus.on('m:update',()=>{v.render()}//当enentsBus触发'm:update'是View刷新
},
events: {事件 }, //事件以哈希表的方式记录存储
add() {+具体实现},
minus() {-具体实现},
mul() {*具体实现},
div() {/具体实现},
autoBindEvents() {自动绑定事件}
}
export default c
二、EventBus 有哪些 API,是做什么用的
一种设计模式或框架,主要用于组件/对象间通信的优化简化。
主要的API有三个:
on : 监听事件
trigger(emit) : 触发事件
off : 取消监听
import $ from 'jquery'
//EventBus.js
class EventBus {
constructor() {
this._eventBus = $(window)
}
on(eventName, fn) {
return this._eventBus.on(eventName, fn)
}
trigger(eventName, data) {
return this._trigger.trigger(eventName, data)
}
off(eventName, fn) {
return this._eventBus.off(eventName, fn)
}
}
export default EventBus
//new.js
import EventBus from 'EventBus.js'
const e = new EventBus()
e.on()
e.trigger()
e.off()
三、表驱动编程
表驱动编程就是将诸多事件进行简化的一种写法,因为这些事件涉及到很多的代码重复问题。
没有表驱动编程的代码:
bindEvents(){
v.el.on('click', '#add1', () => {
m.data.n += 1
v.render(m.data.n)
})
v.el.on('click', '#minus1', () => {
m.data.n -= 1
v.render(m.data.n)
})
v.el.on('click', '#mul2', () => {
m.data.n *= 2
v.render(m.data.n)
})
v.el.on('click', '#divide2', () => {
m.data.n /= 2
v.render(m.data.n)
})
}
运用了表驱动编程的代码(将事件提取出一个哈希表,使逻辑和数据分离开)
events: {
'click #add1': 'add',
'click #minus1': 'minus',
'click #mul2': 'mul',
'click #divide2': 'div',
},
//每个事件点击对应着数据变化的操作函数
add() {
m.update({n: m.data.n + 1})
},
minus() {
m.update({n: m.data.n - 1})
},
mul() {
m.update({n: m.data.n * 2})
},
div() {
m.update({n: m.data.n / 2})
},
autoBindEvents() {
for (let key in c.events) {
const value = c[c.events[key]]
const spaceIndex = key.indexOf(' ')
const part1 = key.slice(0, spaceIndex)
const part2 = key.slice(spaceIndex + 1)
v.el.on(part1, part2, value)
}
}
}
export default c
优点:程序有一个明显的主干,提高了程序的可读性,不必用很多的逻辑语句(if或Case)来把它们找出来的方法。
在简单的情况下,逻辑语句往往更简单而且更直接。但随着逻辑链的复杂,复杂度也会越来越高。表就可以减少重复代码,只将重要的信息放在表里,然后利用表来编程,与逻辑语句相比较有着更稳定的复杂度。
四、模块化的理解:
- 代码模块化后,例如代码变成MVC模式后,修改外观或者更变数据都不用修改其他层,有利于后期代码的维护。
- 业务模块化之后可以使业务流程更为清晰,便于开展工作,各个业务模块之间负责自己模块的业务,也避免了一些不必要的麻烦,使得工作的效率也会更高。
- 一个模块就是一个独立的文件,该文件内部的所有变量,外部无法获取,如果你希望外部能够读取模块内部的某个变量,就必须使用export命令输出该变量,使用import命令输入其他模块提供的功能。