MVC和MVVM模型入门基础知识_模型入门百科

MVC那时计算机世界天地混沌,浑然一体,然后出现了一个创世者,将现实世界抽象出模型形成model,将人机交互从应用逻辑中分离形成view,然后就有了空气、水、鸡啊、蛋什么的。——《前端MVC变形记》MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。Model(模型)Model(模型)是应

MVC和MVVM模型入门基础知识

MVC

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

MVC和MVVM模型入门基础知识_模型入门百科

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和MVVM模型入门基础知识_模型入门百科
接受用户指令时,MVC 可以分成两种方式:
一种是通过 View 接受指令,传递给 Controller。
MVC和MVVM模型入门基础知识_模型入门百科

另一种是直接通过controller接受指令。
MVC和MVVM模型入门基础知识_模型入门百科

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流程图如下:
MVC和MVVM模型入门基础知识_模型入门百科

Vue数据双向绑定原理

数据绑定

双向数据绑定,可以简单而不恰当地理解为一个模版引擎,但是会根据数据变更实时渲染。
MVC和MVVM模型入门基础知识_模型入门百科
不同的MVVM框架中,实现双向数据绑定的技术有所不同。目前一些主流的前端框架实现数据绑定的方式大致有以下几种:

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

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

要实现Vue中的双向数据绑定,大致可以划分三个模块:Observer、Compile、Watcher,如图:
MVC和MVVM模型入门基础知识_模型入门百科

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

数据劫持

一般对数据的劫持都是通过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() 方法完成视图更新。

海计划公众号
(0)
上一篇 2020/03/23 18:37
下一篇 2020/03/23 18:37

您可能感兴趣的内容

  • 程序猿搞笑趣图菜鸟指南_程序员使用说明

    1、客户需求vs最终产品2、程序员的一天寂寞的时候干什么?写程序写程序写程序失恋的时候干什么?写程序写程序写程序发骚的时候干什么?写程序写程序写程序剩下的时候干什么?调程序调程序调程序3、开发平台的差异4、C++ vs C…You have no class(没地位,无级别)…5、凌晨三点,灯火阑珊处十年生死两茫茫,写程序,到天亮。千行代码,Bug何

    2020/04/03
  • Glyphicon Halflings攻略教程一款可以在Bootstrap下免费使用的字体图标

    Glyphicon Halflings基础入门 官方网址:http://glyphicons.com/ 简介描述:一款可以在Bootstrap下免费使用的字体图标  Gl…

    2020/03/05
  • vue 基础知识入门 webpack 前端性能优化入门知识_性能

    背景对于程序开发者而言,开发一个项目不仅仅注重效率和功能,前端的性能问题也是非常重要的。这直接影响用户的体验,从而间接的也反应该项目质量的好坏。 影响项目性能的原因有很多,如:资源文件的大小,业务的繁杂程度等,所以前端优化的方式也很多。这些东西很零碎,容易被人遗忘。优化一: vue-router路由懒加载懒加载: 也叫延迟加载,即在需要的时候进行加载,随用随

    2020/03/20
  • store.js菜鸟指南_一个简单的接口来实现跨浏览器的本地存储

    store.js菜鸟指南 GitHub:https://github.com/marcuswestin/store.js 简介描述:一个简单的接口来实现跨浏览器的本地存储 stor…

    2020/03/06
  • create.js小白入门基于HTML5开发的一套模块化的库和工具

    create.js基础入门 官方网址:http://www.createjs.cc/ GitHub:https://github.com/CreateJS/EaselJS 简介描述…

    2020/03/05
  • Js变量的解构赋值入门百科_解构小白常识

    解构:从数组和对象中提取值,对变量进行赋值。一、数组的解构赋值1.数组的元素是按次序排列的,变量的取值由它的位置决定// 模式匹配let [a, b, c] = [1, 2, 3];let [foo, [[bar], baz]] = [1, [[2], 3]];
    foo // 1
    bar // 2
    baz // 3let [ , , third] = [“f

    2020/03/23
  • JS的不常见写法使用教程_写法使用教程

    1、声明函数并立即执行,返回全局变量,变量的值是一个对象。和声明对象异曲同工。这种算是带变量名的对象声明,不需要new 对象。var demo = function () {function demo1(posterSrc, width, height) {}function demo2(posterSrc, width, height) {}return

    2020/03/30
  • React使用Hooks与Context替代Redux状态管理指南攻略_状态菜鸟指南

    React Hooks 在 2018 年年底就已经公布了,正式发布是在 2019 年 5 月,关于它到底能做什么用,并不在本文的探讨范围之内,本文旨在摸索,如何基于 Hooks 以及 Context,实现多组件的状态共享,完成一个精简版的 Redux。初始化一个 React 项目yarn create create-app hooks-context-bas

    2020/03/26
  • 你真的理解==和===吗?基础知识入门_表达式小白指南

    开门见题说出以下几个表达式的结果var obj1 = { name: ‘张三’}
    var obj2 = obj1
    var obj3 = { name: ‘张三’}null == undefined
    123 == ‘123’
    false == 0
    NaN == false
    obj1 == obj2
    obj1 == obj3补充知识要想回答上述问题,必须理解js

    2020/04/03
  • Js中实现XML和String相互转化菜鸟指南_数据使用帮助

    扩展标记语言 (Extensible Markup Language, XML) 用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 XML使用DTD(document type definition)文档类型定义来组织数据;格式统一,跨平台和语言,早已成为业界公认的标准。XML是标准通

    2020/04/03
  • Unicode®字符百科教程视频_计算机科学领域里的一项业界标准,包括字符集、编码方案

    Unicode®字符百科教程视频 官方网址:https://unicode-table.com/ 简介描述:计算机科学领域里的一项业界标准,包括字符集、编码方案 Unicode(统…

    2020/03/10
  • Sass和Less的区别?小白知识_sass使用教程

    这篇文章主要解答以下几个问题,供前端开发者的新手参考。1、什么是Sass和Less?2、为什么要使用CSS预处理器?3、Sass和Less的比较4、为什么选择使用Sass而不是Less? 什么是Sass和Less?Sass和Less都属于CSS预处理器,那什么是 CSS 预处理器呢?CSS 预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为

    2020/03/29
  • Html5、Css3、ES6的新特性菜鸟知识_特性使用帮助

    Html5的新特性1.语义化标签有利于SEO,有助于爬虫抓取更多的有效信息,爬虫是依赖于标签来确定上下文和各个关键字的权重。语义化的HTML在没有CSS的情况下也能呈现较好的内容结构与代码结构方便其他设备的解析便于团队开发和维护2.表单新特性3.多媒体视频(video)和音频(audio)4.web存储sessionstorage:关闭浏览器清空数据,储存大

    2020/04/03
  • 在Node.js 12 中使用 ESM小白教程_node基础入门

    Node.js 12 之后开始支持 ECMAScript Modules(简称ESM),不过并不是默认开启或者自动切换。坦率地说我也卡了一阵子才搞清楚怎么直接使用。简单记一下吧。首先,Node.js 12 里默认支持的仍是 CommonJS,如果直接按照 ESM 写,然后跑,会报错,错误信息里有个关键字:/cjs/loader.js,只要你看到它,可以肯定是

    2020/03/22
  • 自学web前端达到什么水平,才能满足求职的标准?使用指南_职业入门基础教程

    大多数野生程序员最棘手的问题就是如何依靠技术解决温饱,通俗来讲就是技术折现的问题。如果是单纯出于兴趣,或者只是为了突击某一阶段或者某一项目技术壁垒,不跟就业挂钩的自学倒也是无关痛痒。但是当上岗成为自学的终极目标和结果时,一切都就另当别论了。前端自学者存在的学习误区:1、所学东西可能已过时奉为经典的东西可能已经过时,或者已经有了更好的替代者,而你获取信息的渠道

    2020/03/24
  • 实现一个JS深拷贝函数基础知识入门_函数入门基础教程

    JS深拷贝概念并不新鲜,但是真正要真正理解原理还是有点难度的。这也是JS语言精粹之一吧。例子let a = {name: ‘demo’,age: 18
    };let b = a;
    b.name = ‘demo1’;console.log(a); // 输出 {name: “demo1”, age: 18}
    console.log(b); // 输出 {name

    2020/03/29