浅析 MVC

169 阅读3分钟

一、MVC是什么?

MVC(Model View Controller)是一种架构设计模式.

Mmodel(数据模型)负责操作所有的数据。
Vview (视图)负责所有UI界面。
CController(控制器)对原始数据(Model)进行加工,处理用户的行为和数据model的改变。

优势:这三者关系紧密联系但又互相独立,每一层内部的变化不影响其他层。每一层都对外提供接口(Interface),供上面一层调用。这样一来,软件就可以实现模块化,修改外观或者变更数据都不用修改其他层,大大方便了维护和升级。

Model(数据模型)

let Model = {
  data: { 数据源 },
  create: { 增加数据 },
  delete: { 删除数据 },
  update(data) {
    Object.assign(m.data, data); //用新数据替换旧数据
    eventBus.trigger("m:update"); //eventBus触发'm:update'信息,通知View刷新界面
  },
  get: { 获取数据 },
};

View (视图)

let View={
    el:要刷新的元素,
    html:'要显示在页面上的刷新内容'
    init(){
        v.el:初始化需要刷新的元素
    },
    render(){
        刷新页面
    }
}

Controller (控制器)

let Controller={
    init(){
        v.init()//初始化View
        v.render()//第一次渲染页面
        c.autoBindEvents()//自动的事件绑定
        eventBus.on('m:update',()=>{v.render()}//当enentsBus触发'm:update'是View刷新
    },
    events:{事件以哈希表的方式记录存储},
    //例如:
   events: {
    'click #add1': 'add',
    'click #minus1': 'minus',
    'click #mul2': '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})
    },
    method(){
        data=新数据
        m.update(data) // controller 通知 model去更新数据
    },
    autoBindEvents(){
    	for (let key in c.events) { // 遍历events表,然后自动绑定事件
      const value = c[c.events[key]]
      const spaceIndex = key.indexOf(' ')
      const part1 = key.slice(0, spaceIndex) // 拿到 'click'
      const part2 = key.slice(spaceIndex + 1)  // 拿到'#add1'
      v.el.on(part1, part2, value)
    }
}

二、EventBus

因为MVC(Model View Controller)各个部分是相互独立的,当这三者之间需要通信时,就需要用到EventBus进行这三者之间的监听与通信。

EventBus 常用API

EventBus.on()监听事件
EventBus.trigger()触发事件
EventBus.off()取消监听事件

eventBus.trigger('m:updated') //触发事件 大喊'm 已经更新了'
eventBus.on('m:updated',()=>{ //监听事件 听到后执行函数
     v.render(m.data.n)
     })

三、表驱动程序

所谓的表驱动程序,指的是把一大堆的if...else这样的逻辑处理,转化成从一个hash表中查找key--value对的过程。

例如如果要一个可以返回每个月中天数的函数,用if else:

function iGetMonthDays(iMonth) {
  let iDays;
  if(iMonth === 1) {iDays = 31;}
  else if(iMonth === 2) {iDays = 28;}
  else if(iMonth === 3) {iDays = 31;}
  else if(iMonth === 4) {iDays = 30;}
  else if(iMonth === 5) {iDays = 31;}
  else if(iMonth === 6) {iDays = 30;}
  else if(iMonth === 7) {iDays = 31;}
  else if(iMonth === 8) {iDays = 31;}
  else if(iMonth === 9) {iDays = 30;}
  else if(iMonth === 10) {iDays = 31;}
  else if(iMonth === 11) {iDays = 30;}
  else if(iMonth === 12) {iDays = 31;}
  return iDays;
}

用表驱动程序(包括闰年判断):

const monthDays = [
  [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
  [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
]
function getMonthDays(month, year) {
  let isLeapYear = (year % 4 === 0) && (year % 100 !== 0 || year % 400 === 0) ? 1 : 0
  return monthDays[isLeapYear][(month - 1)];
}
console.log(getMonthDays(2, 2000))

从上面的代码就可体现出用表驱动程序有以下优点:

  • 减少了大量重复代码
  • 提高了代码的可读性

四、模块化

在一个完整的页面应用中,不同的节点功能,不同的结构可以规划为多个模块,每个模块的实现的方式以及用到的技术大不相同,使用模块化编程可以减小各个模块之间的影响和联系,可以更方便的优化代码和重构代码,提高我们代码的重用性,便于后期维护