zoukankan      html  css  js  c++  java
  • JavaScript 中的 MVC、MVP、MVVM

    架构的作用

    参考文章:
    https://www.jianshu.com/p/b42a26623aeb

    一个项目在不断发展过程中,由简单变复杂,随之而来的是臃肿,难维护

    这就需要一个不断演进的架构模式与之匹配,调整出合适的架构,适应项目的发展、增长的团队规模和团队能力,而不是固定不变的架构

    所以我们需要一个好的架构模式,能快速、高效的配合团队开发好一个复杂项目

    今天来简单聊一聊几种设计架构:MVC、MVP、MVVM

    理论总是太苍白,看了就忘,下面我就拿一个登录注册功能的例子来说说我的理解,有错误和补充的地方还望指教


    一、MVC(Model-View-Controller)

    模型-视图-控制器

    这里 View 其实就是 HTML

    架构运行流程

    1、View

    用户点击触发 HTML 上的事件

    • 初始显示登录页面,点击注册按钮触发事件
    • Controller.js 注册了 HTML 中注册按钮的点击事件
    • HTML 请求转发到控制器 Controller.js 上
    <!-- View -->
    <div>
        <div class="main-content">
            <!-- 登录页面内容 -->
        </div>
        <div class="register">注册</div>
    </div>
    
    // Controller.js
    const register = document.getElementsByClassName('register')[0]
    register.addEventListener('click', function(){
        // 点击注册按钮响应事件
    }, false)
    

    2、Controller

    Controller.js 操作 Model.js 的数据

    • HTML 上触发点击事件,Controller.js 响应请求,执行事件逻辑,即请求修改 Model.js 数据
    • Controller.js 通过 Model.js 对外暴露的接口操作数据
      • 例如:展示注册页的变量设置为 true
      • 设置注册页所需要的数据
    // Controller.js
    import Model from './Model.js'
    const register = document.getElementsByClassName('register')[0]
    register.addEventListener('click', function(){
        // 点击注册按钮响应事件
        Model.setSwitch(true)
        let data = {}
        Model.setRegisterData(data)
    }, false)
    

    3、Model

    Model.js 修改数据

    • Model.js 上存有 HTML 显示所用的数据,同时 Model.js 可以修改数据
    • Model.js 对外暴露操作数据的接口
    • 数据更新后, Model.js 操作 HTML 页面更新,即渲染并展示注册页面
    // Model.js
    export default {
        constructor() {
            this.showRegister = false
            this.registerData = {}
        }
        setSwitch(val) {
            this.showRegister = val
        },
        setRegisterData(data) {
            this.registerData = data
            // 因为 View 依赖 Model 的数据
            // Model 不依赖 View
            // View 和 Model 之间使用 观察者模式进行关联
            // Model 变化之后,需要通知依赖他的 View,即使用
            // View 注册的函数 updateContent 更新 View
            updateContent({
                showRegister: this.showRegister,
                registerData: data
            })
        }
    }
    

    4、View

    • HTML 包含了修改自身的逻辑代码,当数据变化后,用来修改 HTML
    <!-- View -->
    <div>
        <div class="main-content">
            <!-- 登录页面内容 -->
        </div>
        <div class="register">注册</div>
    </div>
    <script>
    const classSelector = document.getElementsByClassName
    const mainContent = classSelector('main-content')[0]
    function updateContent(data) {
        // 更新页面
        mainContent.innerHTML = `
        <div>
            <div>展示注册页面:${data.showRegister}</div>
            <div>注册页面内容:${data.registerData}</div>
        </div>`
    }
    </script>
    

    MVC 通讯模式实现

    Model 和 View:

    • Observer 模式,观察者模式
    • View 依赖 Model,Model 不依赖 View,Model 变化之后,需要通知依赖他的 View(通知方式可以是调用 View 提供好的方法)

    实际使用中,HTML 中可能还会绕过 Controller.js,直接调用 Model.js 操作数据,这样 HTML 中会包含一些业务逻辑


    图示流程

    userAction:
    View --> Controller --> Model --> View
    

    二、MVP(Model-View-Presenter)

    模型-视图-中间人

    这里 View 其实就是 HTML

    架构运行流程

    1、View

    用户点击触发 HTML 上的事件

    • 初始显示登录页面,点击注册按钮触发事件
    • Presenter.js 注册了 HTML 中注册按钮的点击事件
    • HTML 请求转发到 Presenter.js 上
    <!-- View -->
    <div>
        <div class="main-content">
            <!-- 登录页面内容 -->
        </div>
        <div class="register">注册</div>
    </div>
    
    // Presenter.js
    const register = document.getElementsByClassName('register')[0]
    register.addEventListener('click', function(){
        // 点击注册按钮响应事件
    }, false)
    

    2、Presenter

    Presenter.js 操作 Model.js 的数据

    • HTML 上触发点击事件,Presenter.js 响应请求,执行事件逻辑,即请求修改 Model.js 数据
    • Presenter.js 通过 Model.js 对外暴露的接口操作数据
      • 例如:展示注册页的变量设置为 true
      • 设置注册页所需要的数据
    // Presenter.js
    import Model from './Model.js'
    const register = document.getElementsByClassName('register')[0]
    register.addEventListener('click', function(){
        // 点击注册按钮响应事件
        Model.setSwitch(true)
        let data = {}
        Model.setRegisterData(data)
    }, false)
    

    3、Model

    Model.js 修改数据

    • Model.js 上存有 HTML 显示所用的数据,同时 Model.js 可以修改数据
    • Model.js 对外暴露操作数据的接口
    • 数据更新后, Model.js 调用 Presenter.js 暴露的接口,更新页面
    // Model.js
    export default {
        constructor() {
            this.showRegister = false
            this.registerData = {}
        }
        setSwitch(val) {
            this.showRegister = val
        },
        setRegisterData(data) {
            this.registerData = data
    
            // 渲染并展示注册页面
            Presenter.updateRegister({
                showRegister: this.showRegister,
                registerData: data
            })
        }
    }
    

    4、Presenter

    Presenter.js 调用 HTML 提供的方法更新页面

    // Presenter.js
    // ...
    
    export default {
        // 更新页面
        updateRegister(data) {
            updateContent(data)
        }
    }
    

    5、View

    Presenter.js 更新 HTML

    • HTML 包含了修改自身的逻辑代码,当数据变化后,用来修改 HTML
    <!-- View -->
    <div>
        <div class="main-content">
            <!-- 登录页面内容 -->
        </div>
        <div class="register">注册</div>
    </div>
    <script>
    const classSelector = document.getElementsByClassName
    const mainContent = classSelector('main-content')[0]
    function updateContent(data) {
        // 更新页面
        mainContent.innerHTML = `
        <div>
            <div>展示注册页面:${data.showRegister}</div>
            <div>注册页面内容:${data.registerData}</div>
        </div>`
    }
    </script>
    

    图示流程

    userAction:
    View --> Presenter --> Model 
    View <-- Presenter <--
    

    MVP 与 MVC 的区别

    • MVC 中 Model 可以与 View 直接交互

    • MVP 中 Model 与 View 完全解耦,交互完全交给 Presenter

    • 上面例子中的区别在于:

      • MVC 中,Model 直接调用 updateContent 修改 HTML,
      • MVP 中,Model 借助 Presenter 去调用 updateContent 修改 HTML
        • MVP 中多了 Presenter 这一步,分开了 Model 和 View
    • 我们目的是实现 UI展示(CSS、HTML)、逻辑(UI动态交互逻辑和业务逻辑)和数据隔离开,那么 MVC 是否能实现呢?

      • 不行,因为 Model 调用 View 提供的方法,两者耦合在一起了;若 View 方法改变,Model 需要随之改变
      • 因为 UI 的交互逻辑是多变的,而 Model 的操作方式是不容易变的,所以 UI 的交互逻辑不应该放在 Model 中,应该提取到 Presenter 中处理
      • 而 MVP 是通过 Presenter 实现 UI 的交互逻辑,若 UI 有变化,Model 不需要改动,修改 Presenter 即可

    三、MVVM(Model-View-ViewModel)

    模型-视图-视图模型

    以 Vue.js 项目为例:

    • View 其实就是 template
    • ViewModel 是组件里面的 js 逻辑
    • Model 既是 Vue 实例中的 data

    架构运行流程

    1、View

    用户点击触发 template 上的事件

    • 初始显示登录页面,点击注册按钮触发事件
    • ViewModel 注册了 template 中注册按钮的点击事件
    • template 请求转发到 ViewModel 上
    <!-- View -->
    <template>
        <div>
            <div class="main-content">
                <template v-if="showRegister">
                    <!-- 注册页面内容 -->
                </template>
                <template v-else>
                    <!-- 登页面内容 -->
                </template>
            </div>
            <div class="register" @click="handleRegister">注册</div>
        </div>
    </template>
    
    // ViewModel
    export default {
        methods: {
            handleRegister() {
                // 点击注册按钮响应事件
            }
        }
    }
    

    2、ViewModel

    ViewModel 操作 data 的数据

    • template 上触发点击事件,ViewModel 响应请求,执行事件逻辑,即请求修改 data 数据
    • ViewModel 通过 Vue.js 提供的方法修改 data
      • 例如:展示注册页的变量设置为 true
      • 设置注册页所需要的数据
    // ViewModel
    export default {
        methods: {
            handleRegister() {
                // 点击注册按钮响应事件
                this.setSwitch(true)
                let data = {}
                this.setRegisterData()
            },
            setSwitch() {},
            setRegisterData() {},
        }
    }
    

    3、Model

    修改数据

    • Model 上存有 template 显示所用的数据
    • 数据更新后, Model 通过双向绑定,通知 ViewModel 更新页面
    // Model.js
    export default {
        data() {
            return {
                showRegister: fasle,
                registerData: {},
            }
        },
        setSwitch(val) {
            this.showRegister = val
        },
        setRegisterData(data) {
            this.registerData = data
        }
    }
    

    图示流程

    userAction:
    View --> ViewModel --> Model 
    View <-- ViewModel <--
    

    MVVM 是 MVP 的演进


    四、总结

    • MVCView视图--Controller控制器--Model模型--View视图 单方向流程结构,目的为分离 View视图与Model模型 ,但是实际使用过程中,View视图与Model模型 分的不够彻底,依旧有耦合行为
    • MVP 为解决这个问题,重新定义了 Controller控制器Presenter中间人 ,彻底分离 View视图与Model模型 ,两者之间的交互全部由 Presenter中间人处理
    • MVVMMVP 的演进,其中 VM 是对 Presenter中间人 的部分功能的自动化提取,例如 HTML 的操作全部由 VM 来做,解放我们的双手,我们只需要关注数据的变化即可

    最后说一句大家常说的:项目开发没有万金油的架构存在,需要根据实际情况不断优化调整;不同的架构适用不同的场景,能用好才是一个合格的工程师。

    都读到最后了、留下个建议如何
  • 相关阅读:
    搭建armlinuxgcc交叉编译工具链环境(Android原生(JNI)开发环境搭建)
    linux vi命令详解
    Android手机在开发调试时logcat不显示输出信息的解决办法
    2012的总结和13的展望
    Gvim编码学习笔记
    vue自定义过滤器格式化时间为年、月、日、小时、分钟、刚刚 J
    学校网站群建设理念
    何为真正网站群?
    手机网站——移动互联网新趋势
    建站是浮云,We7很给力
  • 原文地址:https://www.cnblogs.com/linjunfu/p/14495821.html
Copyright © 2011-2022 走看看