zoukankan      html  css  js  c++  java
  • MVC和MVVM模型

    MVC

    那时计算机世界天地混沌,浑然一体,然后出现了一个创世者,将现实世界抽象出模型形成model,将人机交互从应用逻辑中分离形成view,然后就有了空气、水、鸡啊、蛋什么的。
    ——《前端MVC变形记》

    MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。

    Model(模型)

    Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。

    Model定义了这个模块的数据模型。在代码中体现为数据管理者,Model负责对数据进行获取及存放。

    数据不可能凭空生成的,要么是从服务器上面获取到的数据,要么是本地数据库中的数据,也有可能是用户在UI上填写的表单即将上传到服务器上面存放,所以需要有数据来源。既然Model是数据管理者,则自然由它来负责获取数据。

    MVC允许在不改变视图的情况下改变视图对用户输入的响应方式,用户对View的操作交给了Controller处理,在Controller中响应View的事件调用Model的接口对数据进行操作,一旦Model发生变化便通知相关视图进行更新。

    这里我们把需要用到的数值变量封装在Model中,并定义了add、sub、getVal三种操作数值方法。

    var myapp = {}; // 创建这个应用对象
    
    myapp.Model = function() {
        var val = 0;
    
        this.add = function(v) {
            if (val < 100) val += v;
        };
    
        this.sub = function(v) {
            if (val > 0) val -= v;
        };
    
        this.getVal = function() {
            return val;
        };
    
        /* 观察者模式 */
        var self = this, 
            views = [];
    
        this.register = function(view) {
            views.push(view);
        };
    
        this.notify = function() {
            for(var i = 0; i < views.length; i++) {
                views[i].render(self);
            }
        };
    };

    Model和View之间使用了观察者模式,View事先在此Model上注册,进而观察Model,以便更新在Model上发生改变的数据。

    View(视图)

    View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。

    View,视图,简单来说,就是我们在界面上看见的一切。

    view和controller之间使用了策略模式,这里View引入了Controller的实例来实现特定的响应策略,比如这个栗子中按钮的 click 事件:

    myapp.View = function(controller) {
        var $num = $('#num'),
            $incBtn = $('#increase'),
            $decBtn = $('#decrease');
    
        this.render = function(model) {
            $num.text(model.getVal() + 'rmb');
        };
    
        /*  绑定事件  */
        $incBtn.click(controller.increase);
        $decBtn.click(controller.decrease);
    };

    如果要实现不同的响应的策略只要用不同的Controller实例替换即可。

    Controller(控制器)

    Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。

    Controller是MVC中的数据和视图的协调者,也就是在Controller里面把Model的数据赋值给View来显示(或者是View接收用户输入的数据然后由Controller把这些数据传给Model来保存到本地或者上传到服务器)。

    myapp.Controller = function() {
        var model = null,
            view = null;
    
        this.init = function() {
            /* 初始化Model和View */
            model = new myapp.Model();
            view = new myapp.View(this);
    
            /* View向Model注册,当Model更新就会去通知View啦 */
            model.register(view);
            model.notify();
        };
    
        /* 让Model更新数值并通知View更新视图 */
        this.increase = function() {
            model.add(1);
            model.notify();
        };
    
        this.decrease = function() {
            model.sub(1);
            model.notify();
        };
    };

    这里我们实例化View并向对应的Model实例注册,当Model发生变化时就去通知View做更新,这里用到了观察者模式。

    当我们执行应用的时候,使用Controller做初始化:

    (function() {
        var controller = new myapp.Controller();
        controller.init();
    })();

    通讯

    各部分之间的通信方式如下,所有通讯都是单向的 。

    1. View 传送指令到 Controller
    2. Controller 完成业务逻辑后,要求 Model 改变状态
    3. Model 将新的数据发送到 View,用户得到反馈


    接受用户指令时,MVC 可以分成两种方式:
    一种是通过 View 接受指令,传递给 Controller。

    另一种是直接通过controller接受指令。

    MVC模式的业务逻辑主要集中在Controller,而前端的View其实已经具备了独立处理用户事件的能力,当每个事件都流经Controller时,这层会变得十分臃肿。而且MVC中View和Controller一般是一一对应的,捆绑起来表示一个组件,视图与控制器间的过于紧密的连接让Controller的复用性成了问题。

    MVVM

    MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。

    Model

    我们可以把Model称为数据层,因为它仅仅关注数据本身,不关心任何行为(格式化数据由View的负责),这里可以把它理解为一个类似json的数据对象。

    var data = {
        val: 0
    };

    View

    指的是所看到的页面,和MVC/MVP不同的是,MVVM中的View通过使用模板语法来声明式的将数据渲染进DOM,当ViewModel对Model进行更新的时候,会通过数据绑定更新到View。

    div id="myapp">
        <div>
            <span>{{ val }}rmb</span>
        </div>
        <div>
            <button v-on:click="sub(1)">-</button>
            <button v-on:click="add(1)">+</button>
        </div>
    </div>

    ViewModel

    mvvm模式的核心,它是连接view和model的桥梁。它有两个方向:

    1. 将Model转化成View,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。
    2. 将View转化成Model,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。
    new vue({
        el: '#myapp',
        data: data,
        methods: {
            add(v) {
                if(this.val < 100) {
                    this.val += v;
                }
            },
            sub(v) {
                if(this.val > 0) {
                    this.val -= v;
                }
            }
        }
    });

    总结:

    在MVVM的框架下视图View和模型Model是不能直接通信的。它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信。

    整体来看,比MVC/MVP精简了很多,不仅仅简化了业务与界面的依赖,还解决了数据频繁更新(以前用jQuery操作DOM很繁琐)的问题。因为在MVVM中,View不知道Model的存在,ViewModel和Model也察觉不到View,这种低耦合模式可以使开发过程更加容易,提高应用的可重用性。

    MVVM流程图如下:

    vue数据双向绑定原理

    数据绑定

    双向数据绑定,可以简单而不恰当地理解为一个模版引擎,但是会根据数据变更实时渲染。

    不同的MVVM框架中,实现双向数据绑定的技术有所不同。目前一些主流的前端框架实现数据绑定的方式大致有以下几种:

    • 数据劫持 (Vue)
    • 发布-订阅模式 (Knockout、Backbone)
    • 脏值检查 (Angular)

    Vue采用数据劫持&发布-订阅模式的方式,通过ES5提供的 Object.defineProperty() 方法来劫持(监控)各属性的 getter 、setter ,并在数据(对象)发生变动时通知订阅者,触发相应的监听回调。并且,由于是在不同的数据上触发同步,可以精确的将变更发送给绑定的视图,而不是对所有的数据都执行一次检测。

    要实现Vue中的双向数据绑定,大致可以划分三个模块:Observer、Compile、Watcher,如图:

    • Observer 数据监听器 
      负责对数据对象的所有属性进行监听(数据劫持),监听到数据发生变化后通知订阅者。
    • Compiler 指令解析器 
      扫描模板,并对指令进行解析,然后绑定指定事件。
    • Watcher 订阅者 
      关联Observer和Compile,能够订阅并收到属性变动的通知,执行指令绑定的相应操作,更新视图。Update()是它自身的一个方法,用于执行Compile中绑定的回调,更新视图。

    广州品牌设计公司https://www.houdianzi.com PPT模板下载大全https://redbox.wode007.com

    数据劫持

    一般对数据的劫持都是通过Object.defineProperty方法进行的,Vue中对应的函数为 definereactive ,其普通对象的劫持的精简版代码如下:

    var foo = {
      name: 'vue',
      version: '2.0'
    }
    
    function observe(data) {
        if (!data || typeof data !== 'object') {
            return
        }
        // 使用递归劫持对象属性
        Object.keys(data).forEach(function(key) {
            definereactive(data, key, data[key]);
        })
    }
    
    function defineReactive(obj, key, value) {
         // 监听子属性 比如这里data对象里的 'name' 或者 'version'
         observe(value)
    
        Object.defineProperty(obj, key, {
            get: function reactiveGetter() {
                return value
            },
            set: function reactiveSetter(newVal) {
                if (value === newVal) {
                    return
                } else {
                    value = newVal
                    console.log(`监听成功:${value} --> ${newVal}`)
                }
            }
        })
    }
    
    observe(foo)
    foo.name = 'angular' // “监听成功:vue --> angular”复制代码

    上面完成了对数据对象的监听,接下来还需要在监听到变化后去通知订阅者,这需要实现一个消息订阅器 Dep ,Watcher通过 Dep 添加订阅者,当数据改变便触发 Dep.notify() ,Watcher调用自己的 update() 方法完成视图更新。

  • 相关阅读:
    崩漏
    李翰卿治疗小儿五更咳嗽经验
    34名国宝级名老中医秘方集锦(一)
    黄煌儿科经方
    中医临床参考
    HTML 动态云启动画面
    CANVAS 水波动态背景
    PHP MYSQL单向同步方案
    PHP 获取指定目录下所有文件(包含子目录)
    JS 深度拷贝 Object Array
  • 原文地址:https://www.cnblogs.com/qianxiaox/p/14124603.html
Copyright © 2011-2022 走看看