浅析MVC

84 阅读3分钟

什么是MVC

MVC是一种软件设计模式

  • M - model

模型层,是直接面向最终用户的"视图层"(View)。它是提供给用户的操作界面,是程序的外壳。

  • V - view

视图层,是核心的"数据层"(Model),也就是程序需要操作的数据或信息。

  • C - controller

控制层,是负责根据用户从"视图层"输入的指令,选取"数据层"中的数据,然后对其进行相应的操作,产生最终结果。

EventBus

eventBus是一个对象,它可以用来完成上述M、V、C对象间的通信。 例如,我们希望当M中的数据变化时,能够自动触发V的render,使变化后的数据即时渲染到界面上,如何做到呢? eventsBus提供了on、off、trigger等方法,用来处理事件。我们可以在M的data发生变动时,用trigger方法触发一个事件A(字符串):

m = {
    data: {...},
    methods: {
        ...
        update(data){
            修改m.data
            eventBus.trigger(A)
        }
    }
}
复制代码然后,用on方法监听这个事件A,一旦事件A触发(即数据变化了),就调用V的render重新渲染视图:
eventBus.on(A, ()=>{
    v.render(m.data)
})

如此,就实现了M和V之间的沟通,使得视图和数据保持同步。

表驱动编程

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

例如(使用jQ)

$('#div1).on('click', fn1)
$('#div2).on('click', fn2)
$('#div3).on('click', fn3)
$('#div4).on('click', fn4)
......

当我们给界面上多个元素绑定事件的时候,这样写起来就很麻烦。你可以说我我可以使用事件委托,但如果他们分布在不同的父元素中呢。这就麻烦了。

如果我们利用表驱动编程

events = {
    'click #div1': 'fn1',
    'click #div2': 'fn2',
    'click #div3': 'fn3',
    'click #div4': 'fn4',
  },
fn1 () {}
fn2 () {)
fn3 () {}
fn4 () {}
  autoBindEvents() {
    for (let key in events) {
      const value = events[key]
      const spaceIndex = key.indexOf(' ')
      const part1 = key.slice(0, spaceIndex)
      const part2 = key.slice(spaceIndex + 1)
      v.el.on(part1, part2, value)
    }

这样虽然看起来代码反而变多了,但是如果我们将它放在一个对象里完整封装起来,他的内部是高度解耦的,当代码量越来越多的时候,后续的维护性,以及代码的可读性都是非常高的。

我是如何理解模块化的

模块化有利用代码解耦和复用,这也是软件工程一直在追求的东西。前端模块化的方案

  • 闭包和封装函数

最典型的jQuery,就是利用这个思想。

  • ES6 Modules 在ES6中,从语法层面就提供了模块化的功能。然而受限于浏览器的实现程度,如果想要在浏览器中运行,还是需要通过Babel等转译工具进行编译。ES6提供了import和export命令,分别对应模块的导入和导出功能。具体实例如下:
// demo-export.js 模块定义
var name = "scq000"
var sayHello = (name) => {
  console.log("Hi," + name);
}
export {name, sayHello};

// demo-import.js 使用模块
import {sayHello} from "./demo-export";
sayHello("scq000");
  • Webpack中的模块化方案 作为现代化的前端构建工具,Webpack还提供了丰富的功能能够使我们更加轻易地实现模块化。利用Wepack,你不仅可以将Javascript文件进行模块化,同时还能针对图片,css等静态资源进行模块化,时webpack还可以支持按需加载。
ule.exports = {
  //...
  output: {
    library: 'librayName',
    libraryTarget: 'umd', // 配置输出格式
    filename: 'bundle.js'
  }
};