我理解的 MVC

295 阅读5分钟

MVC历史

MVC最初是在研究Smalltalk-80(1979年)期间设计出来的,恐怕没有一本书能够回到计算机石器时代介绍一下Smalltalk的代码是如何实现MVC的,不仅如此,连想搞清楚当时的应用场景都很难了,都要追溯到80后出生以前的事了。但是当时的图形界面少之又少,施乐公司正在研发友好的用户图形界面,以取代电脑屏幕上那些拒人于千里之外的命令行和DOS提示符。那时计算机世界天地混沌,浑然一体,然后出现了一个创世者,将现实世界抽象出模型形成model,将人机交互从应用逻辑中分离形成view,然后就有了空气、水、鸡啊、蛋什么的。在1995年出版的《设计模式:可复用面向对象软件的基础》对MVC进行了深入的阐述,在推广使用方面发挥了重要作用。

1.MVC 三个对象分别做什么

MVC包括三类对象,将他们分离以提高灵活性和复用性。

  • 模型model用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法,会有一个或多个视图监听此模型。一旦模型的数据发生变化,模型将通知有关的视图。

  • 视图view是它在屏幕上的表示,描绘的是model的当前状态。当模型的数据发生变化,视图相应地得到刷新自己的机会。

  • 控制器controller定义用户界面对用户输入的响应方式,起到不同层面间的组织作用,用于控制应用程序的流程,它处理用户的行为和数据model上的改变。

                                  👆经典MVC模式
                                  👇我理解的mvc
  • M.model 负责操作所有数据
// 数据相关放到 model
const m = {
    data: {
    //初始化数据
    n: parseInt(localStorage.getItem('n'))
    },
    create() { 
    //操作数据
    },
    delete() {
    },
    update(data) {
    Object.assign(m.data, data)//将data的值复制给m.data
    eventBus.trigger('m:updated')//触发事件
    localStorage.setItem('n', m.data.n)//存入数据
    },
    get() {
    }
}
  • V.view 负责UI视图
//视图相关 view
const v = {
    el:要刷新的元素
    html:`展示在页面上的内容`
    init() {
        v.el = $(刷新的元素)
        v.render()//刷新页面
    },
    render()//刷新页面
}
  • C.contronller 负责其他
//示例
let cr={
    init(){
        v.init()//初始化View
        v.render()//第一次渲染页面
        c.autoBindEvents()//自动的事件绑定
        eventBus.on('m:update',()=>{v.render()}//当enentsBus触发'm:update'是View刷新
    },
    events:{事件以哈希表的方式记录存储},
    method(){
        data=新数据
        m.update(data)
    },
    autoBindEvents(){自动绑定事件}
}

2.EventBus 有哪些 API,是做什么用的

  • EventBus有哪些api取决于它搭载的Bus

const eventBus = $(window) //这个Bus就有window的所有api

  • 也可以自己造车👇

基本的api有on(监听事件),trigger(emit)(触发事件),off(取消监听)方法。 用于模块间的通讯,view组件层面,父子组件、兄弟组件通信都可以使eventbus处理

//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.表驱动编程是做什么的

表驱动法是一种编程模式,从表(哈希表)里面查找信息而不是使用逻辑语句(if…else…switch,可以减少重复代码,只将重要的信息放在表里,然后利用表来编程,与逻辑语句相比较有着更稳定的复杂度

下面这段代码相似性很高

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)
  })
}

当我们使用表驱动法后,将事件提取出一个哈希表,使逻辑和数据清晰明了的分离开

events: {
  'click #add1' : 'add',
  'click #minus1' : 'minus',
  'click #mul2' : 'mul',
  'click #divide2' : 'div'
},
add() {
  m.update( data: {n: m.data.n +1})
},
minus() {
  m.update( data: {n: m.data.n -1})
},
mul() {
  m.update( data: {n: m.data.n *2})
},
div() {
  m.update( data: {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)//从0到空格
    const part2 = key.slice(spaceIndex)//从空格切到最后
    v.el.on(part1, part2, value)
    }
}

4.我是如何理解模块化的

1.当一个html文件需要实现多个功能的时候,我们可以把每个功能抽象成一个模块,针对每一个功能开发不同的模块,这使得模块可以独立开发,在工作中,不同的模块也就可以交由不同的开发人员。
2.而且在开发中我们也会用到一些共同API,这个时候我们也可以把这些抽离成一个公用模块,当需要引用这个函数或者功能的时候,只需要在相应的模块里面用import导入相应的包。
3.so模块化开发是一种管理方式,是一种生产方式,一种解决问题的方案,一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块
4.模块化可以降低代码耦合度,减少重复代码,提高代码重用性,并且在项目结构上更加清晰,便于维护。

  • 模块功能主要由两个命令构成:export和import,export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能
  • 一般来说,一个模块就是一个独立的文件,该文件内部的所有变量,外部无法获取,如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量

1.export 模块功能主要由两个命令构成:export和import,export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能 一般来说,一个模块就是一个独立的文件,该文件内部的所有变量,外部无法获取,如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量

2.import import命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块对外接口的名称相同   关于import其实还有很多用法,具体的大家可以查看相关的文档