简介
MVC (Model View Controller), 即 模型 视图 控制器,我觉得这里可以用 内容行为样式分离 来简单理解一下
- 用 html 来写样式?
那么整个 html 中就会充斥着很多无用的标签, html 的逻辑结构会变得很复杂 用 css 来写内容?
代码如下
div::after {
content: 'hello world';
}这样在浏览器呈现的页面上会选不中这个 div,并且 JS 也取不到
- 用 css 表示行为??
IE 时代有过,不过这个 css 不仅要表示样式,还要控制一些复杂逻辑,会使得整个页面加载变慢 JS 控制样式??像如下代码
var $div = $('#x');
那么上面代码
hide
之后div.style.display
就不确定了
模块化
通过前面的描述,我们就知道,需要代码进行模块化了,而想让代码模块之间没有影响,必须要做到如下几点
使用立即执行函数将模块包起来
- 我们不想要全局变量
- 我们要使用局部变量
- ES 5 里面,只有函数有局部变量
- 于是我们声明一个 function xxx,然后 xxx.call()
- 这个时候 xxx 是全局变量(全局函数)
- 所以我们不能给这个函数名字
- function(){}.call()
- 但是 Chrome 报错,语法错误
试出来一种方法可以不报错:
i. !function(){}.call() (我们不在乎这个匿名函数的返回值,所以加个 ! 取反没关系)
ii. (function(){}).call() 不推荐xxx
(function(){}).call() 报错,这种方法会被浏览器当作
xxx(function(){}).call() 执行iii. frank192837192463981273912873098127912378.call() 不推荐, 就是函数名后加一串随机数
使用闭包
如以下代码// 模块一定义
!function() {
var person = {
name: 'frank',
age: 18
}
window.frankGrowUp = function() {
person.age += 1;
return person.age;
};
}.call();
// 模块二调用
!function() {
var newAge = window.frankGrowUp();
console.log(newAge); // 19
}.call();从以上代码可以看出
- 立即执行函数使得 person 无法被外部访问
- 闭包使得匿名函数可以操作 person
- window.frankGrowUp 保存了匿名函数的地址
- 任何地方都可以使用 window.frankGrowUp
=> 任何地方都可以使用 window.frankGrowUp 操作 person,但是不能直接访问 person
然后用 js 文件将这些代码包起来
就是将代码写入到这些 js 文件中,然后在页面上用 script 标签引入即可,注意 js 文件名要与实现代码功能相关
MVC
view 就相当于 html,就是能看得见的那一块东西
controller 属于操作 view 的一些事件逻辑用的,一般 controller 的写法如下let view = document.querySelector();
let controller = function(view) {
// 操作 view 的代码逻辑
...
}
// 调用 controller
controller.call(view);
更高级一点的写法let view = document.querySelector();
let controller = {
view: null,
init: function(view) {
this.view = view;
this.bindEvents(); // 调用定义的事件绑定,这里相当于代码 this.bindEvents.call(this);
},
bindEvents: function() {
let view = this.view;
window.addEventListener('事件', function(){
// 绑定事件操作逻辑代码
...
// active or deactive code according to your condition
});
}
active: function() {
// 激活添加类
},
deactive: function() {
// 去激活添加类
}
};
// 调用 controller, 这里代码相当于 controller.init.call(controller, view);
controller.init(view);
继续优化,使用箭头函数,那么箭头函数外的 this
就可以拿到箭头函数里面使用,而不用担心 this
的指向问题,即箭头函数内外 this
不变,如...
bindEvents: function() {
let view = this.view;
window.addEventListener('事件', ()=> {
console.log(this); // this 在这里就指向 controller
// 绑定事件操作逻辑代码
...
});
}
...
Model 就是模型,跟数据相关,一般来说它的写法是这样var model = { // 获取数据
fetch: function(){
...
return 一个 Promise 对象
},
save: function(name, content) { // 保存数据
...
// 存入数据
return 一个 Promise 对象
}
};
整个 MVC 的逻辑图如下所示
总结代码
Model
window.Model = function(object){ |
View
window.View = function(xxx){ |
Controller
window.Controller = function(options) { |
或者也可以这么写
var model = { |
最后的总结
MVC 是一种设计模式,即 Model View Controller,具体来说他按照功能将代码分成三大块
- Model 层
这一层负责跟 Server 打交道,与 Server 进行请求和响应,保证数据的存储和更新 - View 层
View 层主要是用来展示给用户操作的,即一个操作的界面 - Controller 层
这一层则用来综合控制 view 层以及 Model 层,它监听 view 层的变化,当 view 层有变化时则及时通知 Controller ,然后 Controller 调用 Model 来返回数据并同时更新 view, Molde 则再次请求 Server 进行数据的更新