經(jīng)典MVC模式中,M是指業(yè)務(wù)模型,V是指用戶界面,C則是控制器,使用MVC的目的是將M和V的實(shí)現(xiàn)代碼分離,從而使同一個(gè)程序可以使用不同的表現(xiàn)形式。其中,View的定義比較清晰,就是用戶界面。
1.MVC的三層結(jié)構(gòu)
1.1 M
M即model模型,是指模型表示業(yè)務(wù)規(guī)則(也就是程序需要操作的數(shù)據(jù)或信息)。在MVC的三個(gè)部件中,模型擁有最多的處理任務(wù)。被模型返回的數(shù)據(jù)是中立的,模型與數(shù)據(jù)格式無關(guān),這樣一個(gè)模型能為多個(gè)視圖提供數(shù)據(jù),由于應(yīng)用于模型的代碼只需寫一次就可以被多個(gè)視圖重用,所以減少了代碼的重復(fù)性。
JS代碼示例
const m = { // 模擬數(shù)據(jù)模型
data: { // 使用的數(shù)據(jù)
n: parseInt(localStorage.getItem('n'))
},
create() {},
delete() {},
update(data) { // 修改數(shù)據(jù)
Object.assign(m.data, data)
eventBus.trigger('m:updated')
localStorage.setItem('n', m.data.n)
},
get() {}
}
1.2 V
V即View視圖,是指用戶看到并與之交互的界面。比如由html元素組成的網(wǎng)頁界面,或者軟件的客戶端界面。MVC的好處之一在于它能為應(yīng)用程序處理很多不同的視圖。當(dāng)模型的數(shù)據(jù)發(fā)生變化,視圖相應(yīng)地刷新自己展示出來的頁面。
JS代碼示例
const v = { // 視圖相關(guān)代碼
el: null,
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)
}
}
1.3 C
C即controller控制器,是指控制器接受用戶的輸入并調(diào)用模型和視圖去完成用戶的需求,控制器本身不輸出任何東西和做任何處理。它只是接收請求并決定調(diào)用哪個(gè)模型構(gòu)件去處理請求,然后再確定用哪個(gè)視圖來顯示返回的數(shù)據(jù)。
JS代碼示例
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})
},
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)
}
}
}
三者關(guān)系示意圖

Controller通過調(diào)用相應(yīng)的方法改變Model數(shù)據(jù)模型中的數(shù)據(jù)等,數(shù)據(jù)模型Model的改變時(shí),使視圖隨之變化,視圖由于用戶的點(diǎn)擊觸發(fā)又會通過Controller去改變數(shù)據(jù)模型Model,這是一個(gè)循環(huán)的過程。
2. EventBus
當(dāng)兩個(gè)組件之間毫無關(guān)聯(lián),或者他們之間結(jié)構(gòu)復(fù)雜,但此時(shí)需要傳遞數(shù)據(jù),就需要用到件總線 EventBus的概念。
EventBus能夠簡化各組件間的通信,讓我們的代碼書寫變得簡單,能有效的分離事件發(fā)送方和接收方(也就是解耦的意思),能避免復(fù)雜和容易出錯(cuò)的依賴性和生命周期問題。
EventBus基本的api有 on(監(jiān)聽事件),trigger(emit)(觸發(fā)事件),off(取消監(jiān)聽)方法。用于模塊間的通訊,view組件層面,父子組件、兄弟組件通信都可以使用eventbus 處理。
JS代碼示例
//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()
3. 表驅(qū)動編程
表驅(qū)動方法是一種使你可以在表(哈希表)中查找信息,而不必用邏輯語句(if 或 case)來把他們找出來的方法。
表驅(qū)動編程的意義在于邏輯與數(shù)據(jù)的分離。
JS代碼示例
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)
})
}
將其中重復(fù)部分單獨(dú)使用,相同參數(shù)的不同變量提取出來合成一個(gè)哈希表,使邏輯與數(shù)據(jù)分離。
events: {
"click #add1": "add",
"click #minus1": "minus",
"click #mul2": "mul",
"click #divide2": "divide",
"click #reset": "reset",
},
add() {
m.update({ n: m.data.n + 1 })
},
minus() {
m.update({ n: m.data.n - 1 })
},
mul() {
m.update({ n: m.data.n * 2 })
},
divide() {
m.update({ n: m.data.n / 2 })
},
autoBindEvents() {
for (let key in c.events) {
const value = c[c.events[key]]
const spliceIndex = key.indexOf(" ")
const part1 = key.slice(0, spliceIndex)
const part2 = key.slice(spliceIndex + 1)
v.el.on(part1, part2, value)
}
},
2. JS模塊化語法
模塊化開發(fā)使代碼藕合度降低,模塊化的意義在于最大化的設(shè)計(jì)重用,以最少的模塊、零部件,更快速的滿足更多的個(gè)性化需求。因?yàn)橛辛四K,我們就可以更方便地使用別人的代碼,想要什么功能,就加載什么模塊。但總不能隨便寫吧,總得有規(guī)范讓大家遵守吧。因此ES6出現(xiàn)了模塊化
export(導(dǎo)出)、import(引入)命令
export命令用于規(guī)定模塊的對外接口。
一個(gè)模塊就是一個(gè)獨(dú)立的文件。該文件內(nèi)部的所有變量,外部無法獲取。如果你希望外部能夠讀取模塊內(nèi)部的某個(gè)變量,就必須使用export關(guān)鍵字輸出該變量。
export輸出變量的寫法可以查看cdn文檔。
export命令可以出現(xiàn)在模塊的任何位置,只要處于模塊頂層就可以。如果處于塊級作用域內(nèi),就會報(bào)錯(cuò),下面的import命令也是如此。
import命令用于輸入其他模塊提供的功能。