MVVM模式的理解

MVVM全称Model-View-ViewModel是基于MVCMVP体系结构模式的改进,MVVM就是MVC模式中的View的状态和行为抽象化,将视图UI和业务逻辑分开,更清楚地将用户界面UI的开发与应用程序中业务逻辑和行为的开发区分开来。

描述

MVVM模式简化了界面与业务的依赖,有助于将图形用户界面的开发与业务逻辑或数据模型的开发分离开来。在MVVM中的ViewModel作为绑定器将视图层UI与数据层Model链接起来,在Model更新时,ViewModel通过绑定器将数据更新到View,在View触发指令时,会通过ViewModel传递消息到ModelViewModel像是一个黑盒,在开发过程中只需要关注于呈现UI的视图层以及抽象模型的数据层Model,而不需要过多关注ViewModel是如何传递的数据以及消息。

组成

Model

  • 以面向对象来对对事物进行抽象的结果,是代表真实状态内容的领域模型。
  • 也可以将Model称为数据层,其作为数据中心仅关注数据本身,不关注任何行为。

View

  • View是用户在屏幕上看到的结构、布局和外观,即视图UI
  • Model进行更新的时候,ViewModel会通过数据绑定更新到View

ViewModel

  • ViewModel是暴露公共属性和命令的视图的抽象。
  • ViewModel中的绑定器在视图和数据绑定器之间进行通信。
  • Model更新时,ViewModel通过绑定器将数据更新到View,在View触发指令时,会通过ViewModel传递消息到Model

优点

  • 低耦合: 视图View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
  • 可重用性: 可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。
  • 独立开发: 开发人员可以专注于业务逻辑和数据的开发Model,设计人员可以专注于页面设计。
  • 可测试: 界面素来是比较难于测试的,测试行为可以通过ViewModel来进行。

不足

  • 对于过大的项目,数据绑定需要花费更多的内存。
  • 数据绑定使得Bug较难被调试,当界面异常,可能是View的代码有问题,也可能是Model 的代码有问题,数据绑定使得一个位置的Bug可能被快速传递到别的位置,要定位原始出问题的地方就变得不那么容易了。

实例

下面是参照Vue实现的简单的数据绑定实例,当然对于Vue来说,文档中也提到了Vue没有完全遵循MVVM模型,但是Vue的设计也受到了其启发,https://cn.vuejs.org/v2/guide/instance.html,关于为什么尤大说Vue没有完全遵循MVVM,可以参考这个https://www.zhihu.com/question/327050991

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>数据绑定</title>
  5. </head>
  6. <body>
  7. <div id="app">
  8. <div>{{msg}}</div>
  9. <div>{{date}}</div>
  10. <button onclick="update()">update</button>
  11. </div>
  12. </body>
  13. <script type="text/javascript">
  14. ///////////////////////////////////////////////////////////////////////////////
  15. var Mvvm = function(config) {
  16. this.$el = config.el;
  17. this.__root = document.querySelector(this.$el);
  18. this.__originHTML = this.__root.innerHTML;
  19. function __dep(){
  20. this.subscribers = [];
  21. this.addSub = function(watcher){
  22. if(__dep.target && !this.subscribers.includes(__dep.target) ) this.subscribers.push(watcher);
  23. }
  24. this.notifyAll = function(){
  25. this.subscribers.forEach( watcher => watcher.update());
  26. }
  27. }
  28. function __observe(obj){
  29. for(let item in obj){
  30. let dep = new __dep();
  31. let value = obj[item];
  32. if (Object.prototype.toString.call(value) === "[object Object]") __observe(value);
  33. Object.defineProperty(obj, item, {
  34. configurable: true,
  35. enumerable: true,
  36. get: function reactiveGetter() {
  37. if(__dep.target) dep.addSub(__dep.target);
  38. return value;
  39. },
  40. set: function reactiveSetter(newVal) {
  41. if (value === newVal) return value;
  42. value = newVal;
  43. dep.notifyAll();
  44. }
  45. });
  46. }
  47. return obj;
  48. }
  49. this.$data = __observe(config.data);
  50. function __proxy (target) {
  51. for(let item in target){
  52. Object.defineProperty(this, item, {
  53. configurable: true,
  54. enumerable: true,
  55. get: function proxyGetter() {
  56. return this.$data[item];
  57. },
  58. set: function proxySetter(newVal) {
  59. this.$data[item] = newVal;
  60. }
  61. });
  62. }
  63. }
  64. __proxy.call(this, config.data);
  65. function __watcher(fn){
  66. this.update = function(){
  67. fn();
  68. }
  69. this.activeRun = function(){
  70. __dep.target = this;
  71. fn();
  72. __dep.target = null;
  73. }
  74. this.activeRun();
  75. }
  76. new __watcher(() => {
  77. console.log(this.msg, this.date);
  78. })
  79. new __watcher(() => {
  80. var html = String(this.__originHTML||'').replace(/"/g,'\\"').replace(/\s+|\r|\t|\n/g, ' ')
  81. .replace(/\{\{(.)*?\}\}/g, function(value){
  82. return value.replace("{{",'"+(').replace("}}",')+"');
  83. })
  84. html = `var targetHTML = "${html}";return targetHTML;`;
  85. var parsedHTML = new Function(...Object.keys(this.$data), html)(...Object.values(this.$data));
  86. this.__root.innerHTML = parsedHTML;
  87. })
  88. }
  89. ///////////////////////////////////////////////////////////////////////////////
  90. var vm = new Mvvm({
  91. el: "#app",
  92. data: {
  93. msg: "1",
  94. date: new Date(),
  95. obj: {
  96. a: 1,
  97. b: 11
  98. }
  99. }
  100. })
  101. function update(){
  102. vm.msg = "updated";
  103. }
  104. ///////////////////////////////////////////////////////////////////////////////
  105. </script>
  106. </html>

每日一题

  1. https://github.com/WindrunnerMax/EveryDay

参考

  1. https://zhuanlan.zhihu.com/p/38296857
  2. https://baike.baidu.com/item/MVVM/96310
  3. https://www.liaoxuefeng.com/wiki/1022910821149312/1108898947791072

MVVM模式的理解的更多相关文章

  1. Android Mvvm模式的理解

    1. Mvvm是什么,Mvvm是怎么来的?Mvvm模式广泛应用在WPF项目开发中,使用此模式可以把UI和业务逻辑分离开,使UI设计人员和业务逻辑人员能够分工明确. Mvvm模式是根据MVP模式来的,可 ...

  2. MVC模式和MVVM模式简单理解

    相信这是两个耳熟能详的词了,MVC广泛的用到了java的各种框架当中,比如Struts2, SpringMVC等,作为B/S架构开发,MVS模式也是我们必须掌握的. mvc一步一步演化之后有了现在的M ...

  3. MVC,MVVM模式的理解

    基本上,我们的产品就是通过接口从数据库中读取数据,然后将数据经过处理展示到用户看到的视图上.当然我们还可以从视图上读取用户的输入,然后通过接口写入到数据库.但是,如何将数据展示到视图上,又如何将用户的 ...

  4. WPF MVVM模式的一些理解

    /*本文转自 http://www.cnblogs.com/sirkevin/archive/2012/11/28/2793471.html */ 使用WPF+Mvvm开发一年多,期间由于对Mvvm模 ...

  5. MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息

    MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二 ...

  6. MVVM模式和在WPF中的实现(二)数据绑定

    MVVM模式解析和在WPF中的实现(二) 数据绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...

  7. MVVM模式和在WPF中的实现(一)MVVM模式简介

    MVVM模式解析和在WPF中的实现(一) MVVM模式简介 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在 ...

  8. [转载]MVVM模式原理分析及实践

    没有找到很好的MVVM模式介绍文章,简单找了一篇,分享一下.MVVM实现了UI\UE设计师(Expression Blend 4设计界面)和软件工程师的合理分工,在SilverLight.WPF.Wi ...

  9. 转:界面之下:还原真实的 MVC、MVP、MVVM 模式

    前言 做客户端开发.前端开发对MVC.MVP.MVVM这些名词不了解也应该大致听过,都是为了解决图形界面应用程序复杂性管理问题而产生的应用架构模式.网上很多文章关于这方面的讨论比较杂乱,各种MV*模式 ...

  10. IOS的MVC和MVVM模式简明介绍

    iOS中的MVC(Model-View-Controller)将软件系统分为Model.View.Controller三部分,结构图如下: Model: 你的应用本质上是什么(但不是它的展示方式) C ...

随机推荐

  1. [java] JSP post 提交乱码 解决方案

    //在post提交的页面顶部插入下列代码 <% request.setCharacterEncoding("UTF-8"); %>

  2. [转帖]解Bug之路-NAT引发的性能瓶颈

    https://zhuanlan.zhihu.com/p/286532997 解Bug之路-NAT引发的性能瓶颈 笔者最近解决了一个非常曲折的问题,从抓包开始一路排查到不同内核版本间的细微差异,最后才 ...

  3. 关于信创CPU测试的一些想法和思路

    关于信创CPU测试的一些想法和思路 背景 最近荷兰政府颁布了关于半导体设备出口管制的最新条例. 好像45nm以下的工艺的设备都可能收到限制. 对中国的相关厂商比如长鑫还有华虹的影响应该都比较大. 认为 ...

  4. [转帖]IPv6地址解析库,窥探IPv6地址中包含的信息

    https://zhuanlan.zhihu.com/p/479028720 大家好,我是明说网络的小明同学. 今天和大家介绍一个IPv6 地址解析库IPv6 address Parser :http ...

  5. [转帖]拜托!面试请不要再问我Spring Cloud底层原理

    https://www.cnblogs.com/jajian/p/9973555.html 概述# 毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术.不过大 ...

  6. JVM启动参数脚本的再学习与研究

    JVM启动参数脚本的再学习与研究 摘要 学无止境 前段时间一直再研究JVM参数调优. 但是最近也在想不应该仅研究如何调优. 因为不管怎么设置, 总有猪队友会把环境搞崩. 所以应该想办法在无人值守的情况 ...

  7. 使用shell进行简单分析增量更新时间的方法

    使用shell进行简单分析增量更新时间的方法 思路 产品里面更新增量时耗时较久, 想着能够简单分析下哪些补丁更新时间久 哪些相同前缀的补丁更新的时间累积较久. 本来想通过全shell的方式进行处理 但 ...

  8. Find -mtime 的图解

  9. 配置elementuI菜单

    :unique-opened="true" 只保留一个菜单 :router="true"开启路由标识 index="users" 是标识 它 ...

  10. Gin-官方文档

    目录 官方文档 官方文档 https://learnku.com/docs/gin-gonic/2018/gin-readme/3819 https://www.kancloud.cn/shuangd ...