浅析MVC

62 阅读3分钟

MVC是什么

MVC基本解释

MVC是一种设计模式,其思路是将一个应用程序的代码分为三个模块,每个模块可以写成三个对象,分别是M,V,C 。

M — Model (数据模型)负责操作所有数据

V — View (数据模型)负责所有UI页面

C — Controller (控制器)负责其他

不使用MVC设计思想前,我们写前端代码是写在html、css、js文件中,再在html文件中分别引入css文件和js文件。这样将所有代码不管实习何种功能的都全部糅杂在一个文件中的方式不利于代码维护。

MVC设计思想有一个最小知识原则,将一整个程序代码分功能模块,每个功模块对应一个css 和js文件, 在main.js里面引入各个功能模块的js文件,再在各功能模块的js文件中引入相对应模块的css文件。这样每次新增加功能只需要在main.js中引入js(import './app1.js';),然后再在js中分别引入jquery和相对应模块的css文件。

import $ from 'jquery';
import './app1.css';
//在模块1的js文件中引入模块1的css文件和jquery文件

实行最小知识原则后,将JS文件里面的代码按照M V C的功能区分(M数据 V视图 C控制)封装为M V C对象。

MVC代码示例

代码示例1:

实现一个需求,点击按钮可使页面中的数字加1。

不使用MVC设计思路的代码:

//index.html
<section id="app1">
    <div class="output">
      <span id="number">1</span>
    </div>
  <div class="actions">
      <button id="add1">+1</button>
  </div>
</section>

//main.js
const $button1 = $('#add1');
const $number = $('#number');
const n = localStorage.getItem("n");
$number.text(n || 1);
$button1.on("click",()=>{
   let n = parseInt($number.text());
   n+=1;
   localStorage.setItem("n",n);
   $number.text(n);
});

下面是使用MVC设计思路的代码:

数据相关都放m对象

const m = {
  data:{
    n:const n = localStorage.getItem("n");
  }
}

视图相关都放v对象

const v = {
  html:'<section id="app1">
    <div class="output">
      <span id="number">1</span>
    </div>
  <div class="actions">
      <button id="add1">+1</button>
  </div>
</section>',
update(){
      c.ui.number.text(n || 1);
},
    
  render(){
  const $element = $(v.html).appendTo($('body'))
  //使用最小知识原则将html元素直接写在js文件中,使用.appendTo将js文件中定义的html元素加到html文件的body中
}
}

其他都放c对象

const c = {
ui:{
button1: $('#add1');
number: $('#number');
},
bindEvent(){
 c.ui.button1.on("click",()=>{
   let n = parseInt(c.ui.number.text());
   n+=1;
   localStorage.setItem("n",n);
   $number.text(n);
});
}

}

使用MVC设计思路的代码已经按照基本思路将代码分为3模块,这不是最终成型的,有些重复的地方还可以再简化,这只是举例。

在代码量不多的情况下,使用MVC思想代码量看起来更多更复杂,但实际上MVC已经将各模块共同使用部分的代码进行的整合,提高了代码的复用率。使用MVC设计思路后,当需求变更时,需要改变的代码更少。

表驱动编程

表驱动编程是解决大量重复的代码,在进行重构时都会用数据结构里面哈希表以字符串的形式来存储重复的数据,需要用到里面的数据时,就遍历哈希表,根据 key 得到需要的数据。

上文代码示例2:

上文代码示例1是实现 点击按钮使页面中的数字加1 的功能,现在变更一下需求,分别有加1、减1、乘2、除2四个按键,点击不同按键时可以实现相对应的加减乘除。

示例1使用mvc思想的代码中的bindEvent(){}会变为

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( data: {n: m.data.n +1})
},
minus() {
  m.update( data: {n: m.data.n -1})
},
mul() {
  m.update( data: {n: m.data.n *2})
},
div() {
  m.update( data: {n: m.data.n /2})
}

EventBus

eventBus 主要用于对象间通信。使用 eventBus 可以满足最小知识原则,m 和 v 互相不知道对方的细节,但是却可以调用对方的功能

EventBus中常用API分别是:on、trigger、off

on:用来监听事件

this.on('m:updated', () => {
      this.render(this.data)
    })

trigger:用来自动触发事件

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

off:用来取消绑定事件

自身对于MVC的理解

MVC是一种编程思路,将代码模块化,就像是对大量繁杂的代码进行整理收纳的方法。将实现不同功能的代码相同的部分进行整合,减少重复代码,让代码结构更加清晰利落,便于后期的代码维护。