MVC概念
MVC是一种代码的设计模式。一般对于一个项目代码来说它的模块可以分为主要的三个对象:model、view、controlor。
这三个单词的首字母组成了这种设计模式的名称:
M-Model(数据模型)负责操作数据;
V-View(视图)负责所有UI界面;
C-Controlor(控制器)负责其他。
每个不同的开发领域有不同的解释,大体上还是围绕着这个结构核心的。
下面给出伪代码示例:
(1)M:
const m = {
data: {
n: parseInt(localStorage.getItem('n'))
},//获取数据
create() {},//增
delete() {},//删
update(data) {
Object.assign(m.data, data)
eventBus.trigger('m:updated')
localStorage.setItem('n', m.data.n)
},//改
get() {}
}//查
复制代码
}
(2) V:
const v = {
el: null,//接受一个容器
html: `//生成HTML
<div>
<div class="output">
<span id="number">{{n}}</span>
</div>
<div class="actions">
<button id="add1">+1</button>
<button id="minus1">-1</button>
<button id="mul2">*2</button>
<button id="divide2">÷2</button>
</div>
</div>
`,
init(container) {
v.el = $(container)
},//初始化容器
render(n) {
if (v.el.children.length !== 0) v.el.empty()
$(v.html.replace('{{n}}', n))
.appendTo(v.el)
}//通过if else判断容器的后代是否存在进行增删,最后渲染到页面
}
复制代码
3.C:
const c = {
//初始化容器
init(container) {
v.init(container)
v.render(m.data.n) // view = render(data)
c.autoBindEvents()//自动绑定事件
eventBus.on('m:updated', () => {
console.log('here')
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
复制代码
EventBus以及常用API
EventBus即以事件为驱动的消息服务总线。
EventBus能够简化各组件间的通信,让我们的代码书写变得简单,能有效的分离事件发送方和接收方,能避免复杂和容易出错的依赖性。
EventBus API:
eventBus.getListenerCountOfEvent(eventName):返回给定事件的侦听器数。
eventBus.once(eventName,listenerFunction):将侦听器添加到将仅被调用一次的事件中,该函数执行后,会将其从该事件的侦听器数组中删除。
eventBus.on(eventName,listenerFunction):向事件添加侦听器,每次发出事件时都会调用该侦听器。
eventBus.off(eventName,listenerFunction):从给定事件中删除侦听器。
eventBus.emit(eventName,args):发出一个事件,该事件导致从发出的事件中调用所有侦听器功能,可以传递参数以便侦听器的功能可以访问。
eventBus.getAllEventsName():返回EventBus中的所有事件名称。
eventBus.getAllListenersOfEvent(eventName):返回给定事件的所有侦听器。
eventBus.removeAllListenersOfEvent(eventName):从事件中删除所有侦听器。
简单的代码示例:
import $ from 'jquery'
class EventBus {
constructor() {
this._eventBus = $(window)
}
on(eventName, fn) {
return this._eventBus.on(eventName, fn)
}
trigger(eventName, data) {
return this._eventBus.trigger(eventName, data)
}
off(eventName, fn) {
return this._eventBus.off(eventName, fn)
}
}
export default EventBus
复制代码
表驱动编程的作用
表驱动法就是一种编程模式,从表里面查找信息而不使用逻辑语句。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白。但随着逻辑链的越来越复杂,查表法也就愈发显得更具吸引力。
将四个与按钮绑定的点击触发事件通过表驱动法将普通的event.on('click','id',()=>{})
改写,一般代码量多的时候它的作用才会较大的体现出来。
const c={
events:{//on()的前两个参数提取
'click #addNum':'add',
'click #minusNum':'min',
'click #rideNum':'ride',
'click #besidesNum':'beside'
},
//绑定的触发事件()=>{}
add(){},
min(){},
ride(){},
beside(){},
//调用函数自动执行的方法,遍历构造出event.on('click','id',()=>{})
autoBindEvents(){
for(let key in c.events){
const spaceIndex=key.indexOf(' ')
const part1=key.slice(0,spaceIndex)
const part2=key.slice(spaceIndex+1)
fn(part1,part2,x)
}
}
fn(a,b,c){
event.on(a,b,(c)=>{...})
}
}
复制代码
关于模块化的理解
一个项目的代码可以按照其实现的不同功能,将代码进行按功能作用划分;就像前面提到的MVC三个对象,可以将平常写的代码进行代码重构,划分成不同的模块写到不同的文件中,然后通过调用的方法使之联系起来。这么做的好处自然是将一个项目的代码进行了功能界限地划分,清晰易读,像拆分成一个个模块一样通过调用组合起来还原成为一个完整的项目。
这样划分的话每个模块主要关注的是其实现的功能,主要是精简了代码减少了代码重复;另外一般调用的库直接写到文件开头引用,而且不同的模块可以实现不同库的调用互不影响,后续如果使用不同的库改起来会极大节省时间和精力;需要修改的地方相对没有划分模块的代码来说可谓是事半功倍。