最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • MVC设计模式

    正文概述 掘金(MiaMou)   2021-02-05   566

    「一」MVC三个对象

    • 把页面分成很多模块,每个模块可以写成3个对象,分别是M、V、C
    • M —— Model,数据模型,负责数据相关的任务,操作所有数据(增删改查)
    • V —— View,视图,负责所有UI界面,即用户能看得到的界面
    • C —— Controller,控制器,负责监听用户事件,然后调用 M 和 V 更新数据和视图

    1. Model(数据模型)

    Model 数据管理,包括数据逻辑、数据请求、数据存储等功能。
    前端 Model 主要负责 AJAX 请求或者 LocalStorage 存储。

    伪代码示例

    const model = {
      data: { 初始化数据 },
      create() { 增数据 },
      delete() { 删数据 },
      update(data) { 更新数据 },
      get() { 读数据 }
    }
    
    

    2. View(视图)

    View 负责用户界面,前端 View 主要负责 HTML 渲染。

    伪代码示例

    const view={
        // 需要刷新的元素
        el: null,
        // 显示在页面上的内容
        html: `<div class="html"></div>`,
        // 初始化html
        init(container){
            v.el = $(container)       
        },
        // 刷新页面
        render() { 将数据渲染到页面 }
    }
    

    3. Controller(控制器)

    Controller 负责处理 View 的事件,并更新 Model;也负责监听 Model 的变化,并更新 View,Controller 控制其他的所有流程。

    伪代码示例

    const controller = {
       init(){
          v.init() // view初始化
          v.render() // 第一次渲染 view = render(data)
          c.autoBindEvents() // 自动绑定事件
          eventBus.on('m:update', () => { v.render() }) // 当eventBus触发'm:update'时View刷新
       },
       events:{ 事件以哈希表方式记录 },
       method() {
          data = 改变后的新数据
          m.update(data)
       },
       autoBindEvents() { 自动绑定事件 }
    }
    

    4. MVC实例

    一个加减乘除计算器
    每次点击对应的按钮,数值就会变,基本思想就是监听click事件。

    其MVC操作如下:

    代码展示

    import './app1.css'
    import $ from 'jquery'
    
    const eventBus = $(window)
    
    //数据相关 都放到 M
    const m = {
        data: {
            // 初始化数据n,从本地数据库拿到的数字n
            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(){}
    }
    
    //视图相关 都放到 V
    const v = {
        el: null,
        html: `
        <div>
        <div class="output">
            <span id="number">{{n}}</span>
        </div>
        <div>
            <button id="add1">+1</button>
            <button id="minus1">-1</button>
            <button id="mul2">×2</button>
            <button id="divide2">÷2</button>
        </div>
        </div>
        `,
        // 初始化html
        init(container){
            v.el = $(container)       
        },
        // 将数据渲染到页面
        render(n){
            if(v.el.children.length === null){ // 如果没有渲染过
            } else {
                v.el.empty()
            }
            $(v.html.replace('{{n}}', n)).appendTo(v.el)
        },
    }
    
    //其他 都 C
    const c = {
        init(container){
            v.init(container)   // 第一次渲染html
            v.render(m.data.n)  // 第一次 view = render(data)
            c.autoBindEvents()   // 绑定事件
            eventBus.on('m:updated', ()=>{
                v.render(m.data.n)
            })
        },
        events: {
            'click #add1': 'add',
            'click #minus1': 'minus',
            'click #mul2': 'mul',
            'click #divide2': 'div'
        },
        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)
            }
        },
        add(){
            m.update({n: m.data.n + 1})
        },
        minus(){
            m.update({n: m.data.n - 1})
        },
        mul(){
            m.update({n: m.data.n * 2})
        },
        div(){
            m.update({n: m.data.n / 2})
        }
    }
    
    export default c
    

    「二」 EventBus

    • EventBus 就是 EventTarget
    • EventBus也是一种设计模式或框架,主要用于组件/对象间通信的优化简化。
      • 比如在上面的例子中,Model 数据模型 和View 视图模型彼此不知道彼此的存在,但是又需要通信,于是就要用到EventBus
    • 优势 使用 eventBus 可以满足最小知识原则,m 和 v 互相不知道对方的细节,但是却可以互相调用对方的功能;代码简洁;速度快且轻量。

    EventBus API

    • eventBus 提供了 onofftrigger 等 API,on 用于监听事件,trigger 用于触发事件,off 用于取消监听

    代码实例

    • 在JS文件中自己声明一个EventBus,来模拟使用EventBus的功能。为了方便起见,这里通过引入jquery实现。
    import $ from 'jquery'
    
    const eventBus = $(window)
    
    • 在一个地方使用on方法,另外一个地方使用trigger方法,就初步实现了数据通信功能。
      • 在上面的MVC模型中, Model数据模型更新时,会 trigger 触发一个事件
      • 然后在controller会用 on 监听事件, 通知 view 模型去重新渲染页面
    const m = {
      ....
      update(data) {
        Object.assign(m.data, data)
        eventBus.trigger('m:updated')  // 通知一下view层,我已经更新了数据,view该开始工作了
        localStorage.setItem('n', m.data.n)
      },
      ....
    }
    
    const c = {
      init(container) {
        v.init(container)
        v.render(m.data.n) // view = render(data)
        c.autoBindEvents()
        eventBus.on('m:updated', () => {   // 用 on  监听事件, 通知 view 模型去重新渲染页面
          console.log('here')
          v.render(m.data.n)
        })
      },
      ... 
    }
    

    「三」表驱动编程

    • 表驱动法(Table-Driven Approach),简单讲是指用查表的方法获取值。
    • 表驱动法是一种编程模式,表里可以存数据,也可以存指令,或函数等都可以。
    • 在数值不多的时候我们可以用逻辑语句(if/else 或 case do)的方法来获取值,但随着数值的增多逻辑语句就会越来越长,此时我们可以用表驱动编程,把用来做If条件判断的值存进一个哈希表,然后从表里取值。
    • 表驱动编程在 JavaScript 中的一个重要应用是自动绑定事件。

    代码展示

    在上面的MVC实例中,加减乘除四个按钮我需要分别判断是哪一个按钮被点击,再修改output的值,
    用事件委推,绑定事件中有jquery的事件监听方法。

    --------用事件委托后-------
      const c = {
        init(container) {
            v.init(container)
            v.render(m.data.n)
            c.BindEvents()   //绑定事件
        }
        BindEvents() {
            //jquery对象
            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)
            })
        }
    }
    

    但上面的代码,有很多重复的地方。用表驱动编程可以简化这些代码。把那些相同相似的地方“隐藏”,只留下需要的。

    解决步骤:1. 绑定加减乘除按钮的父元素,只用一个事件监听 2.用哈希表存下按钮和按钮对应的操作

    const c = {
        init() {
            ...
            // 称为自动绑定事件
            c.autoBindEvents()
        },
        // 事件 用 哈希表
        events: {
            'click #add1': 'add',
            'click #minus1': 'minus',
            'click #mul2': 'mul',
            'click #divide2': 'div'
        },
        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)
            }
        },
        add(){
            m.update({n: m.data.n + 1})
        },
        minus(){
            m.update({n: m.data.n - 1})
        },
        mul(){
            m.update({n: m.data.n * 2})
        },
        div(){
            m.update({n: m.data.n / 2})
        }
    }
    

    「四」模块化

    • 一个web页面,根据不同的功能可以分出不同的模块,每个模块的实现方式和使用的技术等等都不相同,引入模块化,可以切断每个模块的相互影响,使得单个模块中可以更好的优化代码。

    • 一个模块就是一个独立的文件,该文件内部的所有变量,外部无法获取,如果外部想读取模块内部的某个变量,ES6的语法里引入了importexport用来实现。

    • 模块化可以降低代码耦合度,减少重复代码,提高代码重用性,并且在项目结构上更加清晰,便于维护。

    References

    1. developer.mozilla.org/zh-CN/docs/…
    2. zhuanlan.zhihu.com/p/96985491

    起源地下载网 » MVC设计模式

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元