浅析MVC

105 阅读2分钟

1. 什么是 MVC

M(Model)数据模型,负责操作数据。

V(View)视图,负责所有的 UI 界面。

C(Controller)控制器,负责监听用户事件,然后调用 M 和 V 更新数据和页面。

//Model 示例
const Model = {
    data:{数据源},
    create(){增加数据},
    delete(){删除数据},
    update(){ //更新数据
        Object.assign(m.data, data)
    	eventBus.trigger('m:updated')
    	localStorage.setItem('n', m.data.n.toString())
    },
    get(){读取数据}
}

//View 示例
const View = {
    el: '需要展示的元素',
    html: '需要展示的元素内容',
    init(){
        初始化需要展示的元素
    }
    render(){
        渲染需要展示的元素
    }
}

//Controller 示例
const Controller = {
  init(container) {
    v.init(container)  //初始化View
    v.render(m.data.n)  //第一次渲染页面
    c.autoBindEvents()  //绑定事件
    //事件触发时刷新页面
    eventBus.on('m:updated', () => {
      v.render(m.data.n)
    })
  },
  events: {
    'click #add1': 'add',
    'click #minus1': 'minus',
    'click #mul2': 'mul',
    'click #divide2': 'divide'
  },
  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 spaceIndex = key.indexOf(' ')
      const part1 = key.slice(0, spaceIndex)
      const part2 = key.slice(spaceIndex + 1)
      v.el.on(part1, part2, value)
    }
  }
}

2. EventBus

EventBus 主要用于对象间的通信,提供了 onofftrigger 等 API,on 用于监听事件,trigger 用域触发事件。使用 EventBus 可以满足最小知识原则,使得 Model 和 View 互不知道对方细节,但可以调用对方的功能。

对于上面代码,Model 在数据更新时,会使用 trigger 触发一个事件,Contrller 中回去监听这个事件,然后调用 View 重新渲染页面

const Model = {
    ...
    update(){ //更新数据
        Object.assign(m.data, data)
    	eventBus.trigger('m:updated')  //触发事件
    	localStorage.setItem('n', m.data.n.toString())
    },
    ...
}
const View = {...}
const Controller = {
  init(container) {
    v.init(container)  
    v.render(m.data.n)  
    c.autoBindEvents()
    eventBus.on('m:updated', () => {
      //事件触发时刷新页面
      v.render(m.data.n)
    })
  },
	...
}

3. 表驱动编程

表驱动方法是一种使你可以在表中查找信息,而不必用逻辑语句(if 或 case)来把他们找出来的方法。事实上,任何信息都可以通过表来挑选。在简单的情况下,逻辑语句往往更简单而且更直接。但随着逻辑链的复杂,表就变得越来越富于吸引力了。(《代码大全》)

表驱动编程可以减少重复代码,只讲重要的信息放在哈希表里,然后利用哈希表来编程,实现逻辑与数据的分离。

function translate(n) {
    if (term === '1') {
        return '一'
    } else if (n === '2') {
        return '二'
    } else if (n === '3') {
        return '三'
    } else {
        return '未知'  
    }
}

对于上面代码,如果想增加一个词条,就需要添加一个 if...else 结构,而使用表驱动编程,只需要添加一个新的表项,不需要修改逻辑。

function translate(n) {
    let terms = {
        '1': '一',
        '2': '二',
        '3': '三'
        '4': '四'   // 添加一个新的词条
    }
    return terms[n];
}

4. 模块化

模块化就是把大段代码中相对独立的代码抽取出来,使之成为一个个的模块。使得代码开发调试效率高,可维护性强,且避免阻断。

可使用如下代码引入和导出模块

export {a, b, c}  //可以导出函数,var,let,const和类
export default randomSquare  //默认导出

import $ from 'jquery'  //导入默认
                        //等同于import {default $} from 'jquery'

重命名导入

// inside module.mjs
export { function1, function2 };

// inside main.mjs
import { function1 as newFunctionName,
         function2 as anotherNewFunctionName } from '/modules/module.mjs';