MAC
通信方式如下:
- View 传送指令到 Controller
- Controller 完成业务逻辑后,要求 Model 改变状态
- Model 将新的数据发送到 View,用户得到反馈
例子如下:
<h1>Number: <span id="num"></span></h1>
<h1>Number: <span id="num1"></span></h1>
<h1>Number: <span id="num2"></span></h1>
<p> <button id="btn">+</button> </p>
<p> <button id="btn1">-</button> </p>
<p> <button id="btn2">+</button> </p>
<script>
var Model = {
data: { // 挂载数据
num: 0
},
changeNumber(type) { // 更改状态
this.data.num += type === 'add' ? 1 : -1
this.noticeView('num', this.data.num) // 通知视图
},
noticeView() { // 通知视图
View.render(...arguments)
},
init() {
this.noticeView('num', this.data.num)
}
}
// View 负责数据的展示 接收到Model的通知去渲染视图 , 接收用户操作后给Controller发送指令
var View = {
elements: { // 保存视图承载dom
num: [document.querySelector('#num'), document.querySelector('#num1'), document.querySelector(
'#num2')]
},
render(key, value) { // 展示数据
this.elements[key].forEach(element => {
element.innerHTML = value
});
},
bindEvents() {
document.querySelector('#btn').onclick = Controller.changeNumber
document.querySelector('#btn1').onclick = Controller.changeNumber
document.querySelector('#btn2').onclick = Controller.changeNumber
},
init() {
this.bindEvents()
}
}
// Controller 接收到view的指令,然后
var Controller = {
changeNumber() { // 接收到View的指令,要求model进行更新
switch (this.innerHTML) {
case '+':
Model.changeNumber('add');
break;
case '-':
Model.changeNumber('reduce');
break;
}
},
init() {
Model.init()
View.init()
}
}
</script>
MAP
通信方式如下:
- 各部分之间的通信,都是双向的。
- View 与 Model 不发生联系,都通过 Presenter 传递。
- View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
例子如下:
<h1>Number: <span id="num"></span></h1>
<h1>Number: <span id="num1"></span></h1>
<h1>Number: <span id="num2"></span></h1>
<p> <button id="btn">+</button> </p>
<p> <button id="btn1">-</button> </p>
<p> <button id="btn2">+</button> </p>
<script>
// Model 挂载数据 接收到Controller的要求,进行状态的更改,
var Model = {
data: { // 挂载数据
num: 0
},
changeNumber(type) { // 更改状态
this.data.num += type === 'add' ? 1 : -1
}
}
// View 负责数据的展示 接收到Model的通知去渲染视图,接收用户操作后给Controller发送指令
var View = {
elements: { // 保存视图承载dom
num: [document.querySelector('#num'), document.querySelector('#num1'),
document.querySelector('#num2')
]
}
}
var Presenter = {
changeNumber(e) { // 接收到View的指令,要求model进行更新
switch (e.target.innerHTML) {
case '+':
Model.changeNumber('add');
break;
case '-':
Model.changeNumber('reduce');
break;
}
// 通知view
this.render('num', Model.data.num) // 通知视图
},
render(key, value) { // 展示数据
View.elements[key].forEach(element => {
element.innerHTML = value
});
},
noticeView() { // 通知视图
View.render(...arguments)
},
bindEvents() {
document.querySelector('#btn').onclick = this.changeNumber.bind(this)
document.querySelector('#btn1').onclick = this.changeNumber.bind(this)
document.querySelector('#btn2').onclick = this.changeNumber.bind(this)
},
init() {
this.bindEvents()
}
}
</script>
MVVM
通信方式如下:
基本和MVP模式一样,但是MVVM采用双向绑定:View的变动,自动反映在 ViewModel,反之亦然。Angular 和 Ember还有很火的Vue都采用这种模式。
例子如下:
<div id="app">
<!-- View -->
<h1>Number: {{num}}</h1>
<p> <button @click = "changeNumber('add')">+</button> </p>
</div>
<script src="./base/vue.js"></script>
<script>
// Model
let model = {
data: { num: 0 },
methods: {
changeNumber (type) {
this.num += type === 'add' ? 1 : -1
}
}
}
// ViewModel 能通过指令来自动得知view层的用户操作,而且利用双向双击绑定,当viewmodel得知数据更改后,view也会自动进行更新
new Vue({
el: '#app',
data: model.data,
methods: model.methods
})
<script>