zoukankan      html  css  js  c++  java
  • 前端MVC

    MVC介绍

    MVC的解释千千万,唯一统一的认识就是MCV分别指model、view、controller,至于其它的咱也不知道对错。
    MVC是把业务按照M、V、C的功能进行解耦:
    Model用来管理业务逻辑相关的数据以及对数据的处理方法
    View=render(data)用来展示Model里数据的当下状态,并实时跟随Model更新
    Controller负责接受并响应View上用户的交互行为以及对Model内部数据进行操作
    刚学编程时,为了完成一个功能,我们想到什么写什么,只要最后能凑出来就成。这种代码常称为“意大利面条”代码,就是一坨*的意思,而且面条之间没有章法可循,你不知道它从哪来,也不知道它到哪去,一旦项目大起来,改代码的工作量比从头写的工作量还大,事情朝着不可控的方向发展了去,改代码的人就很惨。

    于是,理清业务逻辑,形成代码规范,方便日后维护,就显得异常重要,so前端开始借鉴后端的架构设计模式,实现了各种MV*框架
    (1)第一步

    import './app.css'
    import $ from 'jquery'
    
    // 数据相关都放到m
    const m = {
      data: {
        n: parseInt(localStorage.getItem('n'))
      }
    }
    // 视图相关都放到v
    const v = {
      el: null,
      html: `
      <div id="add">{{n}}</div>
      <button id="btn">+1</button>
      `,
      render(n) {
        $(v.html.replace('{{n}}', n))
          .appendTo($('body>#app'))
      }
    }
    // 其他都放c
    const c = {
      init() {
        c.ui = {
          $number: $('add'),
            $btn: $('btn')
        }
        c.bindEvents()
      },
      bindEvents(){
        c.ui.$btn.on('click', ()=>{
          let n = m.data.n
          n+=1
          localStorage.setItem('n', n)
          c.ui.$number.text(n)
        })
      }
    }
    
    v.render()
    c.init()
    

    (2)第二步

    import "./app.css"
    import $ from "jquery"
    import Model from "./base/Model.js"
    import View from "./base/View"
    
    
    const m = new Model({
      data: {
        //初始化数据
        n: parseFloat(localStorage.getItem('n')) || 100,
      },
      update: function(data){
        Object.assign(m.data, data)
        m.trigger('m:updated')
        localStorage.setItem('n', m.data.n.toString())
      }
    })
    
    const init = (el)=>{
      new View({
        el: el,
        data: m.data,
        // 初始化html
        html: `
        <div class="output">
          <span id="number">{{n}}</span>
        </div>
        <div class="actions">
          <button id="add">+1</button>
        </div>`,
        render(data){
          if(this.el.children.length !== 0) this.el.empty()
          $(this.html.replace('{{n}}', data.n)).appendTo(this.el)
        },
        events: {
          'click #add': 'add',
        },
        add(){
          m.update({n: m.data.n + 1})
        },
      })
    }
    
    export default init
    

    表驱动编程

    表驱动编程就像封装函数,函数参数(包括)与存在映射关系的对象一一对应,来减少大量重复代码。
    再拿上面的例子来说,加上减、乘、除的功能:

    events: {
      'click #add': 'add',
      'click #sub': 'sub',
      'click #mul': 'mul',
      'click #div': 'div',
    },
    add(){
      m.update({n: m.data.n + 1})
    },
    sub(){
      m.update({n: m.data.n - 1})
    },
    mul(){
      m.update({n: m.data.n * 2})
    },
    div(){
      m.update({n: m.data.n / 2})
    }
    

    可以简化成

    for(let item in this.events) {
      const operate = this[this.events[item]]
      const spaceIndex = item.indexOf(' ')
      const eventName = item.slice(0, spaceIndex)
      const element = item.slice(spaceIndex+1)
      this.el.on(eventName, element, operate)
    }
    

    EventBus

    上面的例子可以看到,View既要从M中取数据,还会根据用户操作来改变M中的数据,这中间少不了两个层之间的交互,以及监听,这就要EventBus来镇场子了。如何监听data的改变的呢?

    Model:m.trigger('m:updated')
    View:m.update({n: m.data.n + 1})
    

    当data改变时,会调用m.update()方法,此方法里的m.tigger('m:updated')会有一个专门的机制来监听它,就是下面的this.on,监听到m:updated就立即从新渲染页面那一块的数据。

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

    在层层封装之下,底层都离不开EventBus的事件监听,因为数据是活的,会被传递。这里我们可以自己造一个事件,来满足不同条件下的监听需求。然后通过继承,让每个实例都有监听功能。

    • 在jQuery中,有$on,$off,$trigger()来实现监听、解除监听、触发;
    • 在Vue中,则是$on,$off,$emit来实现此功能。

    参考链接:https://efe.baidu.com/blog/mvc-deformation/

  • 相关阅读:
    fastadmin表单弹窗按钮显示为数据库数据
    fastadmin根据栏目获取全部文章
    关于Ubuntu系统的音频录制和播放以及bug解决
    GCC、G++升级
    Install protoc3(Protobuf)
    java学习day12--类与类之间的关系
    java学习day11--接口
    java学习day11--抽象类
    java面试基础题2
    java学习day10--final关键字
  • 原文地址:https://www.cnblogs.com/fourther/p/13343076.html
Copyright © 2011-2022 走看看