简易的MVVM双向数据绑定原理

  1 //数据源
  2 let data = {
  3   message: "hello word",
  4   info: {
  5     job: "web It",
  6     level: "p8"
  7   }
  8 };
  9 //对数据源劫持拦截
 10 class Observer {
 11   constructor(data) {
 12     //需要观察劫持的对象
 13     this.data = data;
 14     //给对象设置get,set
 15     this.observer(this.data);
 16   }
 17   observer(data) {
 18     //对数据源所有的属性添加get,set
 19     Object.keys(data).forEach(key => {
 20       this.defineReactive(data, key, data[key]);
 21       //如果data[key]还是一个对象
 22       if (data[key] instanceof Object) {
 23         this.observer(data[key]);
 24       }
 25     });
 26   }
 27   defineReactive(data, key, value) {
 28     let dep = new Dep();
 29     Object.defineProperty(data, key, {
 30       enumerable: true,
 31       configurable: true,
 32       get() {
 33         Dep.target && dep.add(Dep.target);
 34         return value;
 35       },
 36       set(newValue) {
 37         //如果新旧值变化
 38         if (value !== newValue) {
 39           value = newValue;
 40           dep.notify();
 41         }
 42       }
 43     });
 44   }
 45 }
 46 //定义一个监听watcher
 47 class Watcher {
 48   constructor(data, key, callback) {
 49     //保存数据源
 50     this.data = data;
 51     //保存取值key
 52     this.key = key;
 53     //保存回调
 54     this.callback = callback;
 55     //保存老值
 56     this.oldValue = this.get(this.data, this.key);
 57   }
 58   getExpressionValue(data, expr) {
 59     let expression = expr.split("."),
 60       [length] = expression;
 61     return expression.reduce((prev, next, index) => {
 62       if (index === length - 1) {
 63         return prev[expression[1]];
 64       }
 65       return prev[next];
 66     }, data);
 67   }
 68   //触发获取值的操作
 69   get(data, key) {
 70     //当每一次去数据源获取值的时候把watcher自身赋值给Dep订阅类上
 71     Dep.target = this;
 72     let val = this.getExpressionValue(data, key);
 73     Dep.target = null;
 74     return val;
 75   }
 76   update() {
 77     //取出设置完的值就行新旧比对
 78     let newValue = this.getExpressionValue(this.data, this.key);
 79     newValue !== this.oldValue && this.callback(newValue);
 80   }
 81 }
 82 //创建订阅发布
 83 class Dep {
 84   constructor() {
 85     //订阅者列表
 86     this.subscribeLists = new Set();
 87   }
 88   add(watcher) {
 89     //添加订阅
 90     this.subscribeLists.add(watcher);
 91   }
 92   notify() {
 93     this.subscribeLists.forEach(watcher => watcher.update());
 94   }
 95 }
 96 
 97 function getExpressionValue(data, expr) {
 98   let expression = expr.split("."),
 99     [length] = expression;
100   return expression.reduce((prev, next, index) => {
101     if (index === length - 1) {
102       return prev[expression[1]];
103     }
104     return prev[next];
105   }, data);
106 }
107 
108 //取值
109 function getVal(key) {
110   new Watcher(data, key, newValue => {
111     text.innerHTML = newValue;
112   });
113   return getExpressionValue(data, key);
114 }
115 //对数据源进行劫持
116 const observer = new Observer(data);
117 
118 let text = document.querySelector("#text");
119 text.innerHTML = getVal("info.level");
120 document.querySelector("#input").addEventListener("input", e => {
121     data.info.level = e.target.value
122 });
原文地址:https://www.cnblogs.com/yangliulang/p/10083294.html