一、MVC 是什么
1.基本介绍
MVC这个设计模式认为每个模块都可以写成三个对象,分别是 M、V、C
- M - Model(数据模型)负责操作所有数据
- V - View(视图)负责所有 UI 界面
C - Controller(控制器)负责其他(比如负责监听用户事件,然后调用 M 和 V 更新数据和视图;来处理各种逻辑和数据转化)
2.示例说明
Model示例:
const eventBus = $(window) // 全局变量eventBus;用于对象间的通信const m = {data: {// 数据源},create() {// 增数据},delete() {// 删数据},update(data) { // 更新数据Object.assign(m.data, data) // data里的数据赋值到 m.data.neventBus.trigger('m:updated') // 触发事件localStorage.setItem('n', m.data.n) // 存储数据},get() {// 获取数据}}
View示例:
const v = {el: null, // 容器html: ` `, // 渲染 htmlinit(container) {v.el = $(container) // v.el变成用jquery封装的对象},render() {} // 新增或重新渲染}
Controller示例:
const c = {// 初始化并且绑定事件init(container) {v.init(container)v.render(m.data) // view = render(data);第一次渲染c.autoBindEvents()eventBus.on('m:updated', () => {v.render(m.data)}) // 监听到m里数据更新时触发render},events: {// 事件(哈希表形式存储)},autoBindEvents() {for (let key in c.events) { }}} // 遍历c.events,自动绑定事件
二、关于 EventBus
1.基本作用:
EventBus主要用于对象间通信- 使用
EventBus可以满足最小知识原则,m 和 v 互相不知道对方的细节,但是却可以调用对方的功能2.EventBus的一些API
EventBus提供了on(监听事件)、off(移除一个事件处理函数)和trigger(触发事件)等API ```javascript eventBus.trigger(‘m:updated’)
eventBus.on(‘m:updated’, () => { v.render(m.data) })
- [x] 用`trigger`触发`m`里的`updated`之后,`on`事件监听到之后执行`v.render`;从而实现模块间的通信<a name="lOIdn"></a># 三、表驱动编程<a name="53a0x"></a>## 1.基本的定义与作用- 这里的表指的是**哈希表**;简单的理解为**用哈希表来整理重复代码**- **作用:**可以减少重复代码,只将**重要的信息**放在表里,然后利用表来编程<a name="DRI4c"></a>## 2.示例:<a name="ei1Ay"></a>#### 原本有四个事件,我们需要去绑定这四个事件;原始的写法:```javascript// 首先需要获取到这四个事件const $button1 = $('#add1')const $button2 = $('#minus1')const $button3 = $('#multiply2')const $button4 = $('#divide2')//然后再一个个的绑定事件$button1.on("click",() => {let n = parseInt($number.text())n += 1localStorage.setItem('n', n) // 存储数据,页面刷新之前的数据也还在$number.text(n)})$button2.on("click",() => {let n = parseInt($number.text())n -= 1localStorage.setItem('n', n)$number.text(n)})$button3.on("click",() => {let n = parseInt($number.text())n *= 2localStorage.setItem('n', n)$number.text(n)})$button4.on("click",() => {let n = parseInt($number.text())n /= 2localStorage.setItem('n', n)$number.text(n)})
- 可以看到永远都是在做重复的事情,只有部分区别
-
使用表驱动编程之后的写法:
// 重要的数据提取出来写成哈希表的形式events: {'click #add1': 'add','click #minus1': 'minus','click #multiply2': '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)}}
[x] 但是可以看到,第一种基本都是在做重复性动作,而第二种却基本没有什么重复的地方
[x] 随着事件数的增加,只需要在表中加一行,并且只需要关键词即可
四、个人对于模块化的理解
模块化简单的理解为:
将一个整体分离成一个个小的模块;同时各个模块留出一些接口来供他人使用
用比较专业的话来讲:
使用模块化的优点:
[x] 避免了全局变量的污染
- 降低了耦合度,方便多人合作,互不干扰
- 提高代码复用
- 模块化写代码,使得代码逻辑更清晰
- 降低维护难度
注:尽量不要用JS来写CSS的代码(样式与行为分离思想)
比如:不要在JS使用.show()、.hide()、.css()来显示隐藏或改写CSS
而应该使用.addClass()、.removeClass()等来给css添加或移除class,css自己控制有无这个class时的样式
