当前位置:首页 > 简单说明setter getter数据驱动原理 类似vue数据驱动

简单说明setter getter数据驱动原理 类似vue数据驱动

发布于 2018-04-18 阅读 810 次 Vue Javascript ES6

数据双向绑定小练习
首先遍历data 使用Object.defineProperty设置setter 和 getter
在这里我定义了一个observe函数来做这个工作
这样当我们获取data的值的时候就会getter 设置值的时候会触发setter
然后我们需要监听数据的变化,这样我们就需要一个Watcher,
创建一个观察者类Dep用来存储触发观察者Watcher,如何建立watcher和data之间的关系呢
数据变化的时候会触发setter所以我们可以在setter的时候通知观察者数据有变化。
观察者从哪里来呢,我们遍历data的时候在getter里面去添加观察者,我们只需要初始化的时候添加观察者,
所以我们需要有一个判断,我们可以判断Dep.target来区分
创建Wacher类,Watcher具有对比新旧值的能力,通过调用update方法来通知Compile来更新视图
Compile就是一个编译更新视图的类
我这里只是简单的实现了v-bind的绑定ElementNode的小功能,当然真正的双向绑定要复杂的多,
这里只是简单是阐述一下原理。仅供参考。欢迎大家拍砖指正。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. </head>
  7. <body>
  8. <div class="app">
  9. 姓名:<span v-bind="name"></span><div></div>
  10. 年龄:<span v-bind="age"></span>
  11. </div>
  12. <script>
  13. // 设置setter getter
  14. function observe(data) {
  15. if (!data || typeof data !== 'object') {
  16. return;
  17. }
  18. // 取出所有属性遍历
  19. Object.keys(data).forEach(function(key) {
  20. defineReactive(data, key, data[key]);
  21. });
  22. };
  23. function defineReactive(data, key, val) {
  24. var dep = new Dep();
  25. observe(val); // 监听子属性
  26. Object.defineProperty(data, key, {
  27. enumerable: true, // 可枚举
  28. configurable: false, // 不能再define
  29. get: function() {
  30. if(Dep.target){
  31. // 添加订阅者
  32. dep.addSub(Dep.target);
  33. console.log('subs',dep.subs);
  34. }
  35. return val;
  36. },
  37. set: function(newVal) {
  38. console.log('哈哈哈,监听到值变化了 ', val, ' --> ', newVal);
  39. val = newVal;
  40. // 通知订阅者
  41. dep.notify();
  42. }
  43. });
  44. }
  45. // 通过v-bind属性值获对应data里面属性的值
  46. var tools = {
  47. _getVMVal: function(vm, exp) {
  48. var val = vm;
  49. exp = exp.split('.');
  50. exp.forEach(function(k) {
  51. val = val[k];
  52. });
  53. return val;
  54. }
  55. }
  56. // 观察者
  57. function Dep(){
  58. this.subs = []
  59. }
  60. Dep.prototype.addSub = function(watcher){
  61. this.subs.push(watcher)
  62. }
  63. // 每次值有所改变就要遍历所有Watcher
  64. Dep.prototype.notify = function(){
  65. this.subs.forEach(function(watcher){
  66. watcher.update();
  67. });
  68. }
  69. // 订阅者
  70. function Watcher (vm, exp, cb){
  71. this.vm = vm;
  72. this.exp = exp;
  73. this.cb = cb;
  74. this.value = tools._getVMVal(this.vm,this.exp);
  75. }
  76. Watcher.prototype.update = function(){
  77. var oldVal = this.value;
  78. var newVal = tools._getVMVal(this.vm,this.exp);
  79. this.cb(oldVal, newVal);
  80. }
  81. Watcher.prototype.get = function(){
  82. Dep.target = this;
  83. //这里会触发属性的getter,从而添加订阅者
  84. this.value = tools._getVMVal(this.vm, this.exp);
  85. Dep.target = null;
  86. }
  87. // 编译器用来更新视图
  88. function Compile(el, vm){
  89. this.$el = document.querySelector(el);
  90. this.$vm = vm;
  91. this.init();
  92. }
  93. Compile.prototype.init = function(){
  94. this.compileElement();
  95. }
  96. Compile.prototype.compileElement = function(){
  97. var nodes = this.$el.childNodes,
  98. self = this;
  99. [].slice.call(nodes).forEach(function(node){
  100. if (node.childNodes && node.childNodes.length) {
  101. me.compileElement(node);
  102. }
  103. if(node.nodeType == 1){
  104. self.compile(node);
  105. }
  106. })
  107. }
  108. Compile.prototype.compile = function(node){
  109. var nodeAttrs = node.attributes,
  110. self = this;
  111. [].slice.call(nodeAttrs).forEach(function(attr){
  112. if(attr.name.indexOf('v-bind') == 0){
  113. var exp = attr.value;
  114. var val = tools._getVMVal(self.$vm, exp);
  115. node.innerHTML = val;
  116. var w = new Watcher(self.$vm, exp, function(oldVal, newVal){
  117. if(oldVal!==newVal){
  118. node.innerHTML = newVal;
  119. }
  120. });
  121. w.get();
  122. }
  123. });
  124. }
  125. // 初始化调用
  126. var data = {
  127. 'name': '小幺鸡',
  128. 'age': '12'
  129. };
  130. observe(data);
  131. new Compile('.app',data);
  132. data.name = 'XiaoYaoJi'; // 哈哈哈,监听到值变化了 小幺鸡 --> XiaoYaoJi
  133. </script>
  134. </body>
  135. </html>