MVC浅析

254 阅读3分钟

一、MVC

  • M:Model,数据模型,负责操作所有数据,对数据进行增删改查

  • V:View,视图层,负责所有UI界面

  • C:Controller,控制器,负责操作视图层传输的指令,选取数据模型中的的数据,并对其操作

这三层是紧密联系在一起的,但又是互相独立的,每一层内部的变化不影响其他层。每一层都对外提供接口(Interface),供上面一层调用

eg:以一个页面中的数据进行简单计算为例子进行说明

1.png

1.1数据模型

//示例:
const m = {
    data: { n: parseInt(localStorage.getItem('n')) || 100}, //数据源,100为保底值
    create(){},//增加数据
    delete(){},//删除数据
    update(data){ //更新数据
        Object.assign(m.data,data)
        eventBus.trigger('m:updated')//eventBus触发事件,视图层刷新界面
        localStorage.setItem() //用于数据缓存
    },
    get(){}//获取数据
}

1.2视图层

//示例:
const v = {
    el:null,//要刷新的元素
    html: ``, //元素的内容
    init(container) { //插入到哪个容器里面
        v.el = $(container)
    },
    render(n) { //渲染HTML
        if(v.el.children.length !== 0) v.el.empty()
        $(v.html.replace('{{n}}',n))
            .appendTo(v.el)
        }
}

1.3控制器

//示例:
const c = {
    init(container){ 
        v.init(container) //container容器里面进行第一次渲染
        v.render(m.data.n) //view = render(data) ,视图渲染数据
        c.autoBindEvents() //自动绑定事件
        eventBus.on('m:updated',()=>{ //当enentsBus触发'm:update'时View刷新
            v.render(m.data.n)
        })
    },
    //寻找重要元素
   events:{ //事件以哈希表的方式记录存储
       'click #add1':'add',
       'click #minus1':'minus',
       'click #mul2':'mul',
       'click #divide2':'divide'
   },
   add(){
    m.update({n:m.data.n + 1})
   },
   minus(){
    m.update({n:m.data.n - 1})  
   },
   mul(){
    m.update({n:m.data.n * 2})
   },
   divide(){
    m.update({n:m.data.n / 2})
   },
   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)
       }
   }
}
export default c;

二、eventBus

2.2eventBus的作用

eventBus 主要用于组件之间的通信,它能够简化各组件间的通信,让我们的代码书写变得简单,能有效的分离事件发送方和接收方(也就是解耦的意思)

2.1eventBus提供的API

eventBus.on()监听事件

eventBus.trigger()触发事件

eventBus.off()取消监听事件

三、表驱动编程

表驱动编程是一种使你可以在表中查找信息,而不必用逻辑语句(if 或 case)来把他们找出来的方法。

表驱动编程的意义在于逻辑与数据的分离,使重复冗余的代码变的稳定简洁。

假设day的起始值为1,下面的代码就是为了输出某天是星期几

function weekday(day) {
    if(day&7===0){
  	  return '星期天';
    }
    else if(day%7===2){
  	  return '星期二';
    }
    else if(day%7===3){
  	  return '星期三';
    }
    else if(day%7===4){
  	  return '星期四';
    }
    else if(day%7===5){
  	  return '星期五';
    }
    else if(day%7===6){
  	  return '星期六';
    }
}

通过表驱动编程的思想,简化代码如下:

function week(days){
	let weekdays=['星期天','星期一','星期二','星期三','星期四','星期五','星期六'];
  return weekdays[days%7];
}

四、模块化

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

例如1.3所举的例子,数据模型封装好了controller,可以导出接口

export default c; // 默认导出

如果在其他文件,如main.js中引入

import x from './app1.js'

五、总结

  • 最小知识原则
    • 在设计程序时,应当尽量减少对象之间的交互。 如果两个对象之间不必彼此直接通信,那么这两个对象就不要发生直接的相互联系。常见的做法是引入一个第三者对象,来承担这些对象之间的通信作用
  • 事不过三原则
    • 同样的代码写三遍,就应该抽成一个函数
    • 同样的属性写三遍,就应该做成共用属性(原型或类)
    • 同样的原型写三遍,就应该用继承