美文网首页
MVC与JS模块化

MVC与JS模块化

作者: 茜Akane | 来源:发表于2022-01-15 17:53 被阅读0次

    经典MVC模式中,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。其中,View的定义比较清晰,就是用户界面。

    1.MVC的三层结构

    1.1 M

    M即model模型,是指模型表示业务规则(也就是程序需要操作的数据或信息)。在MVC的三个部件中,模型拥有最多的处理任务。被模型返回的数据是中立的,模型与数据格式无关,这样一个模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。
    JS代码示例

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

    1.2 V

    V即View视图,是指用户看到并与之交互的界面。比如由html元素组成的网页界面,或者软件的客户端界面。MVC的好处之一在于它能为应用程序处理很多不同的视图。当模型的数据发生变化,视图相应地刷新自己展示出来的页面。
    JS代码示例

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

    1.3 C

    C即controller控制器,是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。
    JS代码示例

    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})
      },
      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)
        }
      }
    }
    
    三者关系示意图
    MVC.png

    Controller通过调用相应的方法改变Model数据模型中的数据等,数据模型Model的改变时,使视图随之变化,视图由于用户的点击触发又会通过Controller去改变数据模型Model,这是一个循环的过程。

    2. EventBus

    当两个组件之间毫无关联,或者他们之间结构复杂,但此时需要传递数据,就需要用到件总线 EventBus的概念。
    EventBus能够简化各组件间的通信,让我们的代码书写变得简单,能有效的分离事件发送方和接收方(也就是解耦的意思),能避免复杂和容易出错的依赖性和生命周期问题。
    EventBus基本的api有 on(监听事件),trigger(emit)(触发事件),off(取消监听)方法。用于模块间的通讯,view组件层面,父子组件、兄弟组件通信都可以使用eventbus 处理。
    JS代码示例

    //EventBus.js
    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)
        }
    }
    export default EventBus
    //new.js
    import EventBus from 'EventBus.js'
    const e = new EventBus()
    e.on()
    e.trigger()
    e.off()
    

    3. 表驱动编程

    表驱动方法是一种使你可以在表(哈希表)中查找信息,而不必用逻辑语句(if 或 case)来把他们找出来的方法。
    表驱动编程的意义在于逻辑与数据的分离。
    JS代码示例

    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": "divide",
        "click #reset": "reset",
      },
      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) {
          const value = c[c.events[key]]
          const spliceIndex = key.indexOf(" ")
          const part1 = key.slice(0, spliceIndex)
          const part2 = key.slice(spliceIndex + 1)
          v.el.on(part1, part2, value)
        }
      },
    

    2. JS模块化语法

    模块化开发使代码藕合度降低,模块化的意义在于最大化的设计重用,以最少的模块、零部件,更快速的满足更多的个性化需求。因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。但总不能随便写吧,总得有规范让大家遵守吧。因此ES6出现了模块化
    export(导出)、import(引入)命令
    export命令用于规定模块的对外接口。
    一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。
    export输出变量的写法可以查看cdn文档。
    export命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错,下面的import命令也是如此。
    import命令用于输入其他模块提供的功能。

    相关文章

      网友评论

          本文标题:MVC与JS模块化

          本文链接:https://www.haomeiwen.com/subject/ocracrtx.html