浅析MVC

134 阅读3分钟

MVC的介绍

MVC(Model-View-Controller)是一种万金油似的设计模式,所有的页面都可以使用MVC来优化代码结构。

每个模块都可以写成三个对象:分别是M、V、C

M-Model(数据类型)负责操作所有数据

示例代码如下:

// 数据相关都放到m
const m = {
  data: {
    n: parseInt(localStorage.getItem('n'))
  },
  create() {},
  delete() {},
  update(data) {
    Object.assign(m.data, data)
    eventBus.trigger('m:updated')
    localStorage.setItem('n', m.data.n)
  },
  get() {}
}

V-View(视图)负责所有ui界面

示例代码如下:

// 视图相关都放到v
const v = {
  el: null,
  html: `
  <div>
    <div class="output">
      <span id="number">{{n}}</span>
    </div>
    <div class="actions">
      <button id="add1">+1</button>
      <button id="minus1">-1</button>
      <button id="mul2">*2</button>
      <button id="divide2">÷2</button>
    </div>
  </div>
`,
  init(container) {
    v.el = $(container)
  },
  render(n) {
    if (v.el.children.length !== 0) v.el.empty()
    $(v.html.replace('{{n}}', n))
      .appendTo(v.el)
  }
}

C-Controller(控制器)负责其它

示例代码如下:

// 其他都c
const c = {
  init(container) {
    v.init(container)
    v.render(m.data.n) // view = render(data)
    c.autoBindEvents()
    eventBus.on('m:updated', () => {
      console.log('here')
      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})
  },
  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)
    }
  }

EventBus的介绍

我们想实现m.data数据更新的时候提示c.render来重新渲染的时候得用到事件监听和触发,所以我们来引用一个eventBus来实现对象间的通信

部分代码如下:

const eventBus = $(window)//创建eventBus
eventBus.trigger('m:updated')//调用eventBus的trigger触发
eventBus.on('m:updated', () => { //调用eventBus的on注册事件
      console.log('here')
      v.render(m.data.n)
    })

常用的eventBus的Api有:trigger(触发事件)、on(注册事件)、off(取消事件)

表驱动编程

所谓表驱动法(Table-Driven Approach),简单讲是指用查表的方法获取值。 我们平时查字典以及念初中时查《数学用表》找立方根就是典型的表驱动法。在数值不多的时候我们可以用逻辑语句(if 或case)的方法来获取值,但随着数值的增多逻辑语句就会越来越长,此时表驱动法的优势就显现出来了。

比如我们想实现上面的监听事件:

$('#add').on('click', ()=>{
number += 1
$number.text(number)
localStorage.setItem('number', number)
})
$('#minus').on('click', ()=>{
number -= 1
$number.text(number)
localStorage.setItem('number', number)
})
$('#mult).on('click', ()=>{
number *= 2
$number.text(number)
localStorage.setItem('number', number)
})
$('#divide).on('click', ()=>{
number /= 2
$number.text(number)
localStorage.setItem('number', number)
})

但是我们可以用一个哈希表来实现我们的需求,代码如下:

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

表驱动编程的优点

  1. 提高了程序的可读性。
  2. 减少了重复代码。
  3. 降低了复杂度。
  4. 程序有一个明显的主干。

我对模块化的理解

我觉得模块化就是将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起 ,块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信。

比如我们在做一个页面的时候,需要有多个功能,比如可以简单的计算,可以进行TAB切换,可以进行点击移动、可以悬浮变色...这个时候我们可以把几个功能模块化,分成几个模块,我们可以用export导出模块,import引入模块,来实现我们想要的功能,而且代码不会显得那么冗余。

模块化编程的好处有:

多人协作互不干扰 模块化避免了变量污染,并且可以使得分工更加容易 

灵活架构,焦点分离 可以将独立的功能从主干中分离开来单独开发,增加效率

方便模块间组合、分解 、解耦 降低各个功能模块间的耦合度

方便维护和管理 方便单个模块功能调试、升级


前端小白,如有错误请留言指正!!!