当前位置:   article > 正文

Vue.js中的MVVM

vue。js mvvm

MVVM的理解

MVVM拆开来即为Model-View-ViewModel,有View,ViewModel,Model三部分组成。View层代表的是视图、模版,负责将数据模型转化为UI展现出来。Model层代表的是模型、数据,可以在Model层中定义数据修改和操作的业务逻辑。ViewModel层连接Model和View。

在MVVM的架构下,View层和Model层并没有直接联系,而是通过ViewModel层进行交互。ViewModel层通过双向数据绑定将View层和Model层连接了起来,使得View层和Model层的同步工作完全是自动的。因此开发者只需关注业务逻辑,无需手动操作DOM,复杂的数据状态维护交给MVVM统一来管理。在Vue.js中MVVM的体现:

MVVM的原理

在不同的框架当中,MVVM实现的原理是不同的:

脏检查机制:

Angular.js就是采取的脏检查机制,当发生了某种事件(例如输入),Angular.js会检查新的数据结构和之前的数据结构是否发生来变动,来决定是否更新视图。

数据劫持

Vue.js的实现方式,对数据(Model)进行劫持,当数据变动时,数据会出发劫持时绑定的方法,对视图进行更新。

相同点

脏检查机制和数据劫持是有许多相同点的,例如,它们都有三个步骤:

  • 解析模版
  • 解析数据
  • 绑定模版与数据

实现MVVM

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Two-way data-binding</title>
  6. </head>
  7. <body>
  8. <div id="app">
  9. <input type="text" v-model="text">
  10. {{ text }}
  11. </div>
  12. <script>
  13. function observe (obj, vm) {
  14. Object.keys(obj).forEach(function (key) {
  15. defineReactive(vm, key, obj[key]);
  16. });
  17. }
  18. function defineReactive (obj, key, val) {
  19. var dep = new Dep();
  20. Object.defineProperty(obj, key, {
  21. get: function () {
  22. if (Dep.target) dep.addSub(Dep.target);
  23. return val
  24. },
  25. set: function (newVal) {
  26. if (newVal === val) return
  27. val = newVal;
  28. dep.notify();
  29. }
  30. });
  31. }
  32. function nodeToFragment (node, vm) {
  33. var flag = document.createDocumentFragment();
  34. var child;
  35. while (child = node.firstChild) {
  36. compile(child, vm);
  37. flag.appendChild(child);
  38. }
  39. return flag;
  40. }
  41. function compile (node, vm) {
  42. var reg = /\{\{(.*)\}\}/;
  43. // 节点类型为元素
  44. if (node.nodeType === 1) {
  45. var attr = node.attributes;
  46. // 解析属性
  47. for (var i = 0; i < attr.length; i++) {
  48. if (attr[i].nodeName == 'v-model') {
  49. var name = attr[i].nodeValue; // 获取v-model绑定的属性名
  50. node.addEventListener('input', function (e) {
  51. // 给相应的data属性赋值,进而触发该属性的set方法
  52. vm[name] = e.target.value;
  53. });
  54. node.value = vm[name]; // 将data的值赋给该node
  55. node.removeAttribute('v-model');
  56. }
  57. }
  58. new Watcher(vm, node, name, 'input');
  59. }
  60. // 节点类型为text
  61. if (node.nodeType === 3) {
  62. if (reg.test(node.nodeValue)) {
  63. var name = RegExp.$1; // 获取匹配到的字符串
  64. name = name.trim();
  65. new Watcher(vm, node, name, 'text');
  66. }
  67. }
  68. }
  69. function Watcher (vm, node, name, nodeType) {
  70. // this为watcher函数
  71. Dep.target = this;
  72. // console.log(this);
  73. this.name = name;
  74. this.node = node;
  75. this.vm = vm;
  76. this.nodeType = nodeType;
  77. this.update();
  78. Dep.target = null;
  79. }
  80. Watcher.prototype = {
  81. update: function () {
  82. this.get();
  83. if (this.nodeType == 'text') {
  84. this.node.nodeValue = this.value;
  85. }
  86. if (this.nodeType == 'input') {
  87. this.node.value = this.value;
  88. }
  89. },
  90. // 获取daa中的属性值
  91. get: function () {
  92. this.value = this.vm[this.name]; // 触发相应属性的get
  93. }
  94. }
  95. function Dep () {
  96. this.subs = []
  97. }
  98. Dep.prototype = {
  99. addSub: function(sub) {
  100. this.subs.push(sub);
  101. },
  102. notify: function() {
  103. this.subs.forEach(function(sub) {
  104. sub.update();
  105. });
  106. }
  107. };
  108. function Vue (options) {
  109. this.data = options.data;
  110. var data = this.data;
  111. observe(data, this);
  112. var id = options.el;
  113. var dom = nodeToFragment(document.getElementById(id), this);
  114. // 编译完成后,将dom返回到app中
  115. document.getElementById(id).appendChild(dom);
  116. }
  117. var vm = new Vue({
  118. el: 'app',
  119. data: {
  120. text: 'hello world'
  121. }
  122. });
  123. </script>
  124. </body>
  125. </html>
  126. 复制代码
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/581094
推荐阅读
相关标签
  

闽ICP备14008679号