《浅析 MVC》

183 阅读3分钟

MVC 三个对象

MVC 的三个对象,分别为 M、V、C

  • M - Model(数据模型)负责操作所有数据。
  • V - View(视图)是直接面向最终用户的“视图层”,负责所有 UI 界面。
  • C - Controller(控制器)负责根据用户从“视图层”输入的指令,选取“数据层”中的数据,然后对其进行相应的操作,产生最终结果。
const Model = {
  data(){}        //保存数据
  create(){},     //增
  delete(){},     //删
  undate(){},     //改
  get(){}         //查
}
const View = {
  el:null,        //接受一个容器
  html: ``,       //生成HTML
  init(){},       //初始化容器
  render()        //页面渲染
}
const Controller = {
  init(){},       //初始化容器
  events:{},      //用户操作事件
  bindEvents(){}  //绑定事件,响应用户操作
}

EventBus

EventBus 是一种设计模型或框架,主要用于组件/对象间通信

常用 API

  • on 监听事件
  • trigger 自动触发事件
  • off 取消监听

用法:

1. 封装 EventBus

// EventBus.js 
import $ from 'jquery'

class EventBus {
  constructor() {
    // 从 window 上引用来的  
    this._eventBus = $(window)
  }
  on(eventName, fn) {
    return this._eventBus.on(eventName, fn)
  }
  trigger(eventName, data) {
    return this._eventBus.trigger(eventName, data)
  }
  off(eventName, fn) {
    return this._eventBus.off(eventName, fn)
  }
}

// 暴漏出一个接口,方便使用
export default EventBus

2. 用cosnt e = new EventBus()

在 a.js 文件里,new EventBus()即可直接使用on、trigger、off等方法。

// a.js
import EventBus from 'EventBus.js'

const e = new EventBus()

e.on()
e.trigger()
e.off()

或者用 class 继承的方法

  1. 让 Model/View 继承 EventBus
// Model.js
import EventBus from './EventBus'

class Model extends EventBus {
  constructor(options) {
    super()
    const keys = ['data', 'update', 'create', 'delete', 'get']
    keys.forEach((key) => {
      if (key in options) {
        this[key] = options[key]
      }
    })
  }
  create(){}
  delete(){}
  update(){}
  get(){}
}

export default Model
// View.js
import $ from 'jquery'
import EventBus from 'EventBus'

class View extends EventBus{
  // constructor({el, html, render, data, eventBus, events}) {
  constructor(options) {
    super() // EventBus#constructor()
    Object.assign(this, options)
    this.el = $(this.el)
    this.render(this.data)
    this.autoBindEvents()
    // 监听数据变化
    this.on('m:updated', () => {
      this.render(this.data)
    })
  }
}

export default View

3. 在 app.js 里面,使用trigger,自动触发事件

update(data) {
    Object.assign(m.data, data)//把传进来的data直接放在m.data上
    eventBus.trigger('m:updated')//通过trigger自动更新数据
    localStorage.setItem('n', m.data.n)//储存数据
}    

表驱动编程

表驱动法是一种编程模式,从表(哈希表)里面查找信息而不是使用逻辑语句(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({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})
}

如何理解模块化

  1. 代码模块化之后,无论是代码的整体性还是后期进行代码维护,都变的清晰简单了起来。例如与逻辑相关的代码统一放到 JS 文件中,与视图相关的统一放到 html 文件中,与样式相关的统一放到 css 文件中。
  2. 业务模块化之后可以使业务流程更为清晰,便于开展工作,各个业务模块之间负责自己模块的业务,也避免了一些不必要的麻烦,使得工作的效率也会更高。
  3. 模块化我觉得是一种高效的思想,这在编程过程中提供了一种优化代码以及重构代码的方向。