什么是MVC?
MVC是一种设计模式,主要分为M V C 三块。
M:model(数据模型),负责操作所有的数据。
V:view(视图),负责所有UI界面。
C:control(控制器),负责除M和V以外的东西。
我们以一个很简单的小项目举例:

点击按钮会对数字进行计算。
//不使用MVC(伪代码)
let n = result.text() //100
+1.on('click',()=>{
n += 1
localStorage.setItem('number',n)
result.render()
})
-1.on('click',()=>{
n -= 1
localStorage.setItem('number',n)
result.render()
})
*2.on('click',()=>{
n *= 2
localStorage.setItem('number',n)
result.render()
})
/2.on('click',()=>{
n /= 2
localStorage.setItem('number',n)
result.render()
})
//使用MVC
const m = {
n : parseInt(localStorage.getItem('number')) || 100
}
const v = {
render(data){
//将data渲染到页面
localStorage.setItem('number',data)
}
}
const c = {
btn.on('click','-1' ()=>{
n -= 1
render(m.n)
}),
btn.on('click','+1' ()=>{
n += 1
render(m.n)
}),
btn.on('click','*2' ()=>{
n *= 2
render(m.n)
}),
btn.on('click','/2' ()=>{
n /= 1
render(m.n)
})
}
我们可以看到,使用MVC之后,每一个模块都只需要负责自己那一部分的代码即可。
表驱动式编程
我们可以看到上面的代码还是略显繁琐,因为多次调用了on监听事件,我们可以使用表驱动式来将其简化。
//简化前
const c = {
btn.on('click','-1' ()=>{
n -= 1
render(m.n)
}),
btn.on('click','+1' ()=>{
n += 1
render(m.n)
}),
btn.on('click','*2' ()=>{
n *= 2
render(m.n)
}),
btn.on('click','/2' ()=>{
n /= 1
render(m.n)
})
}
//简化后
const c = {
init(){
c.bilndEvents()
}
hash:{
'click -1':sub,
'click +1':add,
'click *2':mul,
'click /2':div,
},
//表
bilndEvents(){
for(let key in c.hash){
const value = c.hash[key]
btn.on(key[0],key[1],value,)
}
},
sub(){
v.render(m.n - 1)
},
add(){
v.reder(m.n + 1)
},
mul(){
v.render(m.n * 2)
},
div(){
v.render(m.n / 2)
}
}
//c.init()
可以看到,使用表驱动式编程后,我们就不在需要去重复监听事件了,并且,代码的逻辑也变得十分清晰,想知道事件如何处理,只需要看一下驱动表即可。
eventBus
上面的代码还有一个问题,它和简化前一样,每次都需要获取n,然后将其渲染进页面。我们可以通过eventBus来监听数据n的变化。
const eventBus = $(window)
//创建eventBus
const m = {
n : parseInt(localStorage.getItem('number')) || 100,
update(data){
Object.assign(m.n, data)
eventBus.trigger('updated')
//n变化时触发
}
}
const c = {
init(){
c.bilndEvents()
eventBus.on('updated',()=>{
v.render(m.n)
})
//一旦触发监听,就重新渲染
}
hash:{
'click -1':sub,
'click +1':add,
'click *2':mul,
'click /2':div,
},
sub(){
m.update(m.n - 1)
},
add(){
m.update(m.n + 1)
},
mul(){
m.update(m.n * 2)
},
div(){
m.update(m.n / 2)
},
bilndEvents(){
for(let key in c.hash){
const value = c.hash[key]
btn.on(key[0],key[1],value,)
}
},
}
使用了eventBus后,事件不在需要关注渲染,只需每次将数字传给update即可。
eventBus监听其实是每一个模块都需要的一个功能,我们还可以通过继承的方式,将其放到M V C 的原型链上。
class EventBus {
constructor(){
this._eventBUs = $(window)
}
on(eventName,fn){
return this._eventBus.on(eventName,dn)
}
trigger(eventName, data) {
return this._eventBus.trigger(eventName, data)
}
off(eventName, fn) {
return this._eventBus.off(eventName, fn)
}
}
export default EventBus
我们常用的eventBus的api为 on , trigger , off
- eventBus.on('string',callbackname)
- eventBus.trigger('string')
- eventBus.off('string',callbackname) //若不传callbackname 即表示取消所有事件监听
模块化
当我们面临一项复杂的需求时,我们可以通过模块化将其分成多个模块(例如MVC),每个模块只负责自己的事情,不去了解外部的参数/数据。
使用这种方法构建的项目,是背景方便进行维护的,因为每个模块之间不存在强烈的耦合关系,且互不影响,因此当我们需要修改某个模块时,不需要关注该模块以外的东西。
常用的命令:
引入:
import '路径'
import x from '路径'
导出:
export default x