浅析MVC

2021-01-26  本文已影响0人  Carlmac

一、MVC是什么?

M 就是 model, 即数据模型,负责数据相关的任务,包括对数据的增删改查

V 就是view, 即视图层,即用户能看得到的界面

C 就是 Controller,控制器,负责监听用户事件,然后调用 M 和 V 更新数据和视图

接下来将分别用伪代码表示三个部分的工作内容

1.1 Model 数据模型

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

1.2 View 视图层

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

1.3 Controller 控制器

控制器就是通过绑定事件,根据用户的操作,调用M和V 更新数据和视图

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

二、EventBus

2.1 EventBus是什么?

EventBus主要用于对象之间的通信,比如在上面的例子中,Model 数据模型 和View 视图模型彼此不知道彼此的存在,但是又需要通信,于是就要用到EventBus

总结:使用 eventBus 可以满足最小知识原则,m 和 v 互相不知道对方的细节,但是却可以调用对方的功能

2.2 EventBus 有哪些API?

eventBus 提供了 on、off 和 trigger 等 API,on 用于监听事件,trigger 用于触发事件

比如在上面的MVC模型中, M数据模型更新时,会 trigger 触发一个事件

const m = {
  ....
  update(data) {
    Object.assign(m.data, data)
    eventBus.trigger('m:updated')  // 通知一下view层,我已经更新了数据,view该开始工作了
    localStorage.setItem('n', m.data.n)
  },
  ....
}

然后在controller,controller会用 on 监听事件, 然后通知 view 模型去重新渲染页面

const c = {
  init(container) {
    v.init(container)
    v.render(m.data.n) // view = render(data)
    c.autoBindEvents()
    eventBus.on('m:updated', () => {   // controller会用 on  监听事件,
      //然后通知 view 模型去重新渲染页面
      console.log('here')
      v.render(m.data.n)
    })
  },
  ... 
}

三、表驱动编程

当我们需要判断3种以上的情况,做出相应的事情,往往需要写很多很多的If else,这样的代码可读性不强, 为了增强代码的可读性,我们可以用表驱动编程,把用来做If条件判断的值存进一个哈希表,然后从表里取值:

const c = {
  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})
  },
  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)
    }
  }

四、模块化

模块化就是把相对独立的代码从一大段代码里抽取成一个个短小精悍的模块

每个模块之间相对独立,方便以后的维护和修改

ES6的语法里引入了Import和export就是用来实现模块化的

当我们在app1.js 里封装好了controller 模型, 然后导出controller:

export default c  // 默认导出
export {c} // 另外一种导出方式。记得要加花括号

在Main.js里我们想用controller:

import x from './app1.js'
等价于import {default as x} from './app1.js'

x.init('#app1')

关于重命名导出的更多例子:

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

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

猜你喜欢

热点阅读