JavaScript中的MVC

174 阅读4分钟

1. MVC 三个对象

M:model(数据模型),负责操作所有数据

//定义数据和对数据的crud方法
const model = {
  data: {
    n: 数据
  },
  create() {},
  delete() {},
  update() {
  数据n更新,顺便触发公共事件
  },
  get() {}
}

v:view(视图),负责所有ui界面

//定义html视图,和视图的初始化以及更新视图方法
const view = {
  el: 接收的是视图元素,真正被展示给使用者,html模板每次被更改后就重新渲染到这里,时刻保持最新
  html: `
 html代码快,用来作为模板,进行数据的替换和更改
`,
  init(container) {
   //获取到主视图中要插入的元素
},
  render(n) {
   //接收新数据n后刷新视图
  }
}

c:controller(控制器),负责其他

//由其他模块直接调用init方法,进行操作的主要场地,调用model和view定义的数据、视图和方法,并可以用来绑定各类事件及其他所有操作
const controller = {
  init(container) {
    v.init(container)
    v.render(数据) 
    c.autoBindEvents()
    eventBus.on('某公共事件', () => {
      v.render(改变后的数据n)
    })
  },
  events: {
    '事件一': '方法一',
    '事件二': '方法二'
  },
  方法一() {
    m.update(操作n)
  },
  方法二() {
    m.update(操作n)
  },
  autoBindEvents() {
  自动绑定事件
  }
}
export default controller//导出controller

2. EventBus

eventBus是一个事件处理平台,该平台可以通过任何JavaScript进行全局访问和触发。可以在总线上添加和删除事件侦听器,也可以在事件总线的帮助下调度事件,如果向事件注册了任何侦听器,则将触发给定的回调。

比如,全局中,无论哪个点击事件被触发,数据被更新时,都触发数据的update方法,于是可以给eventbus绑定一个xx事件,在update中执行触发eventbus上的xx事件,由这个xx事件去执行视图的更新。此时,这个eventBus像是一个公用的api,有添加事件、触发事件、删除事件等api。

//jquery
class EventBus {
    constructor() {
        this._eventBus = $(window)
    }
    on(eventName, fn) {
        return this._eventBus.on(eventName, fn)
    }
    trigger(eventName, data) {
        return this._trigger.trigger(eventName, data)
    }
    off(eventName, fn) {
        return this._eventBus.off(eventName, fn)
    }
}

eventBus应是发布/订阅模式的一种应用。

function EventBus() {
 var eventTopics = {};
//订阅,如果没有对应名字的事件创建该事件并添加订阅者
 this.addEventListener = function(eventName, listener) {
  if (!eventTopics[eventName] || eventTopics[eventName].length < 1) {
   eventTopics[eventName] = [];
  }
  eventTopics[eventName].push(listener);
 };
//发布,如果没有事件就直接返回,否则遍历每个事件中的所有订阅者并执行他的事件方法
 this.emitEventListeners = function(eventName, params) {
  if (!eventTopics[eventName] || eventTopics[eventName].length < 1)
   return;
  eventTopics[eventName].forEach(function(listener) {
   listener(!!params ? params : {});
  });
 }

 this.removeListener = function(eventName, listener) {
  if (!eventTopics[eventName] || eventTopics[eventName].length < 1)
   return;
  // delete listener by event name
  delete eventTopics[eventName];
 };

 this.getListener = function(eventName){
  return eventTopics[eventName];
 }
} //END EventBus

function test(){

 var eventBus = new EventBus();
 var data1 = "some data for event1";
 var data2 = "some data for event2";
 
 //订阅
 // add listener to event1
 eventBus.addEventListener("event1", function(data){
  console.log("listener1 listen event1 -> " + data);
 });
 
 // add listener to event1
 eventBus.addEventListener("event1", function(data){
  console.log("listener2 listen event1 -> " + data);
 });

 // add listener to event2
 eventBus.addEventListener("event2", function(data){
  console.log("listener1 listen event2 -> " + data);
 });
 
 // add listener to event2
 eventBus.addEventListener("event2", function(data){
  console.log("listener2 listen event2 -> " + data);
 });

 //发布
 eventBus.emitEventListeners("event1", data1);
 eventBus.emitEventListeners("event2", data2);
}

test();


//result
listener1 listen event1 -> some data for event1
listener2 listen event1 -> some data for event1
listener1 listen event2 -> some data for event2
listener2 listen event2 -> some data for event2

3. 表驱动编程

代码大全的描述:表驱动法就是一种编程模式,从表里面查找信息而不使用逻辑语句。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白。但随着逻辑链的越来越复杂,查表法也就愈发显得更具吸引力。

表驱动编程,在各种语言中都能应用,通过定义键值对或者数组下标索引的方式,直接获取对应关系。逻辑简单的情况下,if-else简单明了,但是随着逻辑的复杂性越来越大,表驱动的优越性就会越来越明显

在JavaScript中,表驱动法应用于数组和对象

//使用if else

function getMonthDays(month) {
    let days;
    if(1 == month) {days = 31;}
    else if(2 == month) {days = 28;}
    else if(3 == month) {days = 31;}
    else if(4 == month) {days = 30;}
    else if(5 == month) {days = 31;}
    else if(6 == month) {days = 30;}
    else if(7 == month) {days = 31;}
    else if(8 == month) {days = 31;}
    else if(9 == month) {days = 30;}
    else if(10 == month) {days = 31;}
    else if(11 == month) {days = 30;}
    else if(12 == month) {days = 31;}
    return days;
}
//使用表驱动,应用数组
const monthDays = [
    [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
]
function getMonthDays(month) {
    return monthDays[month - 1];
}

//应用对象
const monthDays = {
    1:31,
    2: 28,
    3: 31,
    ...
    12:31
}
function getMonthDays(month) {
    return monthDays[1];
}


表驱动还有其他的应用形式,上面用到的是直接访问表,此外还有索引访问表和阶梯访问表

直接访问表无须绕很多复杂的圈子就能够在表里面找到你想要的信息。

索引访问表也叫分段访问表,是先用一个基本类型的数据从一张索引表中查处一个键值,然后再用这一键值查出你感兴趣的主数据。

阶梯访问表要把每一区间的上限写入一张表里,然后写一个循环,按照各区间的上限来检查分数。当分数第一次超过某个区间的上限时,你就知道相应的等级了。

4. 模块化

模块化主要是将不同功能类型的代码分离开来,分成独立的文件或者代码块,通过相互的引用、传参依然保持联系,是为了代码的解耦,各个小的部分最终组成一个完整项目。mvc便是将代码分解成三个模块,各自负责各自的逻辑,相互联系却又各自独立,使得代码逻辑更加清晰并且易于维护。