MVVM 框架

问题:

1、MVVM 的定义

 

  M (Model): 数据来源,服务器上业务逻辑操作

  V (View): 界面,页面

  VM (ViewModel): view 和 model 的核心枢纽,如 vue.js

  Model 和 ViewModel 的双向关系:

  1、 Model 通过 Ajax (服务器) 通信,发送数据给 ViewModel

  2、 ViewModel 通过 Ajax (服务器) 通信,回传数据给 Model

  View  和 ViewModel 的双向关系

  1、 ViewModel 的数据改变,会映射到 View(即可以即时改变 View 显示的内容)

  2、View 的内容改变,也会同时改变 ViewModel 对应的数据

 

MVVM模式常见于用于构建用户界面的客户端应用

  • 微软的WPF,构建客户端应用的
  • 手机应用,iOS APP, Android APP
  • Web应用

MVVM的设计理念是前端工程化的体现;让展示层展示逻辑,尽可能的交于数据来驱动;使前端工程师从繁琐的DOM操作中解脱处理;使数据的变化直接体现给用户,而不是将数据的变化交于前端工程师后再进行DOM操作展示数据变化

前端MVVM的设计理念是受到后端MVC理念的启发的;在MVC的设计理念中,前端(V)是其中的一个环节,浏览器只负责现有页面的渲染,不关心也无权操作数据

而MVVM 的出现,彻底将前端工程从后台分离出来,使数据的变化处理彻底交由前端操作,而后台只负责数据的处理,不再关心数据变化而带来的展示层的变化

 

  1. 前端开发早期的时候都是操作DOM
  2. 后来使用jQuery让我们提高了操作DOM的效率,但从开发的角度还是在大量的手动操作DOM
  3. MVVM模式让以往手动操作DOM的方式彻底解脱了,它不要用户自己操作DOM,而是将普通数据绑定到ViewModel上,会自动将数据渲染到页面中,视图变化会通知ViewModel层更新数据,数据变化也会通过ViewModel层更新数据,因此MVVM中最重要的角色就是ViewModel,真正意义上把视图和数据实现了解耦,提高了开发效率

 核心:

  • MVVM模式让我们从繁琐的DOM操作中彻底解放了
  • MVVM也叫数据驱动视图

 

2、对比MVC 和 MVVM

  认识MVC: Controller 负责 将 Model 的数据在 View 中显示出来(即 Controller 负责将 Model 的数据赋值给View),比如在controller中写document.getElementById("box").innerHTML = data[”title”],只是还没有刻意建一个Model类出来而已。

    M (Model): 模型,应用程序处理数据的部分,通常指从数据库读取数据

    V  (View): 视图,界面, 应用程序处理界面显示的部分,通常根据模型数据创建

    C (Controller): 控制器, 应用程序控制用户交互的部分,通常负责从View读取数据,控制用户输入,向 Model 发送数据

  斯坦福大学公开课上的这幅图来说明,这可以说是最经典和最规范的MVC标准

    

    从上图可以看出: C可以直接引用 V 和 M, V 和 M 不能(不应该)直接引用 C

    View 和 Controller 之间的交互:

      View 把事件传递给 Controller,Controller 相当于靶子,View 和 Controller 有两种交互方式:一种是: target->action,另一种是:协议->委托,委托有两种方式 代理和数据源:代理是 should,will,did 等等的委托,数据源是 data,count 等等的委托

    Model 和 Controller 之间的交互:

      Model是数据管理者,可理解为它直接和数据库打交道,Model 和 View 应该是一种同步关系,即不管任何时候只要 Model 的数据发生改变,View 显示的内容也应该发生改变。我们可关注 Model 的值发生改变而不用关心 Model 的网络请求是否结束了,Controller 根本不关心Model从哪里拿数据,Controller 的责任是把Model 最新的值赋值给View,Controller 关注的是Model 的值是否发生改变

MVC 的设计思想其实就是在后台代码中对各个阶段代码工作内容不同的分工,从而在实际编码过程中,能够达到专人负责专项的工作理念和开发人员的分工合作。

MVC与编程语言无关,与具体语言的语法规则无关。

核心理念:单一职责,分工协作

优点:

  • 更好的开发效率
  • 更好的可维护性

 

  MVVM 的诞生:

    需要数据有M, 需要界面有V,把M 的数据给V显示,所以有 C,但是我们忽略了一个重要的操作:数据解析,在MVC 时代手机API数据比较简单,很可能一步就解决,那时把数据解析交给 Controller完成,但是现在手机API 数据越来越复杂,数据解析就没有那么简单了,如果继续按照MVC 的设计思路,将数据解析放到C完成,C 将会变得相当臃肿。Controller 设计出来并不是处理数据解析的,而是:1、管理自己的生命周期, 2、处理 Controllder 之间的跳转, 3、 实现 Controller 容器。在MVC 没有谁是负责处理数据解析的,那么将由谁负责处理数据解析呢?没有就创建一个新的类出来,开发者们专门为数据解析创建出一个新的类:ViewModel,于是 MVVM就诞生了

 

  MVVM 的实现:

    在MVVM Controller 的存在感被完全降低了,VM 的出现是Controller 存在感降低的原因。VM 先拿到原始数据,经过数据解析,把结果给Controller,因为 Controller只需要 数据解析的结果而不关心过程,所以相当于 VM 把如何解析Model 的数据封装起来了,C 根本不需要知道这个M 的存在,前提是有VM, 一旦在实现 Controller中遇到任何与Model(数据)有关的问题就找 VM

3、 数据双向绑定的原理

  双向绑定是什么意思?

  

  

  双向是指ViewModel中的data部分和View之间的双向关系。
  正向:数据驱动页面
  反向:页面更新数据

  绑定是指自动化处理,data改变了view随之改变,反之也是。
  不用像传统方式那样,通过onChange事件获取用户输入,然后再通过改变innerHtml修改显示。

 

  双向绑定的原理是什么?可以写出来吗?

  双向绑定都是依赖ES5中一个重要的API,Object.defineProperty。

  正向:

  Object.defineProperty的作用:

    监听到 data的变化,监听到变化后会有个回调函数,在定义的时候直接写回调函数,在Object.defineProperty回调函数写明 view 和 data 的关联关系,后续中data有变化就会自动根据你写的关联处理修改View的显示内容。直接操作修改data是因为 Object.defineProperty 有 set 属性

  反向:

  在view中输入内容时,通过 input 事件(比如 onchange),修改 data。只不过这件事不需要我们程序员自己去写了,有些框架背后在做这件事,比如,在Vue框架中,可以使用V-Model方便的关联view和data。

 

  Object.defineProperty()

  定义:

  Object.defineProperty() 方法是在一个对象新定义一个属性,或者修改一个对象的现有属性,返回修改后的这个对象(换句话就是 修改一个对象返回一个修改后的对象)

  语法:

  Object.defineProperty(obj, prop, descriptor)

  参数:
  obj:要在其上定义属性的对象。
  prop:要定义或修改的属性的名称。
  descriptor:将被定义或修改的属性描述符。

  返回值
  被传递给函数的对象。

  具体解释可看:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

 

  Object.defineProperty 与 Reflect.defineProperty 的区别:

  Object.defineProperty是 ES5 的用法,返回的是一个对象

  Reflect.defineProperty是ES6 的用法,返回的是一个布尔值 

 

Object.defineProperty缺点:

  • 深度监听,需要递归到底,一次性计算量大
  • 无法监听新增/删除属性(所以需要 vue.set vue.delete 实现新增/删除属性)
  • 无法监听原生数组,需要特殊处理

 

 

4、 设计模式 (观察者模式)

  

    1. 监听者 (Observer): 有一个监听者(Observer),监听 data发生的变化, (通过Object.defineProperty 的get 属性重新遍历,修改 get 和 set 操作,还会有一个递归的操作,如果操作的是一个子对象,会对这个子对象重新进行递归遍历一遍保证所有的key值都是有 observer 对象的。)

    2. 观察者列表 (Dep): 数据的变化会触发 Object.defineProperty 对象的set 属性,set 会执行对观察者列表的触发,通知观察者列表(Dep)

    3. 列表会有一个更新函数,通知了它们,它们会自动调用 updated 更新函数,也就是 Dep 调用了 回调,这个 回调是 观察者 (watcher)给的

    4. 观察者(watcher): watcher 拿到更新后的数据就可以更新到 view了

    5. 观察者列表的updated 是怎么传进去的,是通过 watcher 的订阅,watcher 往观察者列表添加新的内容(监听完后会有一步实例化 watcher 对象,想对A 操作,observer 完后会手动调用一下watcher,实例化watcher,watcher 会调用 get,检测watcher全局变量是否有值,有值的话会调用 deep.target,把内容往 Dep添加)

 

posted @ 2020-08-03 15:48  queenya_zhang  阅读(10352)  评论(0编辑  收藏  举报