参考文档

一、页面—>数据

view更新data只需要添加DOM事件监听即可,比如input标签监听 ‘input’ 事件就可以实现

二、数据—>页面

是通过数据代理 + 发布者-订阅者模式的方式来实现的

2-1 数据代理

vue是通过Object.defineProperty()来实现数据代理的

  1. <!--
  2. 1.Vue中的数据代理:
  3. 通过vm对象来代理data对象中属性的操作(读/写)
  4. 2.Vue中数据代理的好处:
  5. 更加方便的操作data中的数据
  6. 3.基本原理:
  7. 通过Object.defineProperty()把data对象中所有属性添加到vm上。
  8. 为每一个添加到vm上的属性,都指定一个getter/setter
  9. getter/setter内部去操作(读/写)data中对应的属性。
  10. -->
  1. let number = 18
  2. let person = {
  3. name: "张三",
  4. sex: '男',
  5. }
  6. Object.defineProperty(person, 'age', {
  7. value: 18,
  8. enumerable: true, // 控制属性是否可以枚举,默认值是false
  9. writable: true, //控制属性是否可以被修改,默认是false
  10. configurable: true, //控制属性是否可以被删除,默认是false
  11. // 当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
  12. get() {
  13. console.log('有人读去了age属性');
  14. return number
  15. },
  16. // 当有人修改person的age属性时,set函数(setter)就会被调用,且收到修改的具体值
  17. set(value) {
  18. console.log('有人修改了age属性,且值是', value);
  19. number = value
  20. }
  21. })
  1. let obj = {
  2. x: 100
  3. }
  4. let obj2 = {
  5. y: 200
  6. }
  7. Object.defineProperty(obj2, 'x', {
  8. get() {
  9. return obj.x
  10. },
  11. set(value) {
  12. obj.x = value
  13. }
  14. })

2-2 发布者订阅模式

  1. //1.消息订阅器,内部维护了所有订阅者的列表
  2. function Dep () {
  3. this.subs = [];
  4. }
  5. Dep.prototype = {
  6. addSub: function(sub) {
  7. this.subs.push(sub);
  8. },
  9. notify: function(value) {
  10. this.subs.forEach(function(sub) {
  11. sub.update(value);
  12. });
  13. }
  14. };
  15. var dep = new Dep();
  16. //2.订阅者
  17. function Watcher() {
  18. }
  19. Watcher.prototype = {
  20. update: function(value){
  21. console.log("数据源已经变动,新的数据是"+value)
  22. }
  23. }
  24. var w1 = new Watcher();
  25. var w2 = new Watcher();
  26. dep.addSub(w1);
  27. dep.addSub(w2);
  28. //3.数据源,通过defineProperty监听数据源的变化
  29. var book = {}
  30. Object.defineProperty(book, 'name', {
  31. set: function (value) {
  32. name = value;
  33. //一旦数据源发生变化了,通知所有的订阅者更新数据
  34. dep.notify(value);
  35. },
  36. get: function () {
  37. return '《' + name + '》'
  38. }
  39. })
  40. book.name = 'vue权威指南'; // 你取了一个书名叫做vue权威指南
  41. book.name = 'vue权威指南2'; // 你取了一个书名叫做vue权威指南
  42. console.log(book.name); // 《vue权威指南》

2-3 数据绑定的实现流程

  • 首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。
  • 因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。
  • 接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。
  • 因此接下去我们执行以下3个步骤,实现数据的双向绑定:
    1. 监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知所有订阅者。
    2. 订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
    3. 解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅者1547815009579.png