zoukankan      html  css  js  c++  java
  • 简易的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 });
  • 相关阅读:
    restful风格
    拦截器(拦截都是控制层的地址。 filter: )
    Springmvc完成ajax功能,controller类返回的数据类型为String且为汉字时出现乱码
    文件上传
    Springmvc完成ajax功能。(jquery. $)
    Controller如何进行重定向跳转
    Maven学习日志一
    SSM整合
    Spring学习日志四
    Spring学习日志三
  • 原文地址:https://www.cnblogs.com/yangliulang/p/10083294.html
Copyright © 2011-2022 走看看