js 脏检测

基础知识

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div>
      <input type="text" ng-bind="name" />
      <button type="button" ng-click="increment">increment</button>
      <div ng-bind="name"></div>
    </div>
    <script>
      class Watcher {
        constructor(name, last, exp, listener) {
          this.name = name; // 数据变量名
          this.last = last; // 数据变量旧值
          this.newVal = exp; // 返回数据变量新值的函数
          this.listener = listener || function () {}; // 监听回调函数,变量“脏”时触发
          this.listener(this.last, this.newVal());
        }
      }

      class Scope {
        constructor() {
          // 观察者数组
          this.watchers = [];
        }

        // 添加数据观察者
        watch(name, exp, listener) {
          this.watchers.push(new Watcher(name, "", exp, listener));
        }

        // 对监视器的新旧值进行对比
        // 当新旧值不同时,调用listener函数进行相应操作
        // 并将旧值更新为新值。它将不断重复这一过程,直到所有数据变量的新旧值相等:
        digest() {
          let dirty = true;
          while (dirty) {
            dirty = false;
            this.watchers.forEach(watcher => {
              let newVal = watcher.newVal();
              var oldVal = watcher.last;
              if (newVal !== oldVal) {
                dirty = true;
                watcher.listener(oldVal, newVal);
                watcher.last = newVal;
              }
            });
          }
        }
      }

      class App extends Scope {
        name = "Ajanuw";

        constructor() {
          super();
        }

        increment() {
          this.name += "+";
        }
      }

      const app = new App();
      run(app);
      function run(app) {
        document // 绑定依赖观察者
          .querySelectorAll("[ng-bind]")
          .forEach(it => {
            const nodeName = it.nodeName.toLowerCase();
            const bindKey = it.getAttribute("ng-bind");
            if (bindKey in app) {
              app.watch(
                bindKey,
                () => app[bindKey],
                (oldVal, newVal) => {
                  if (nodeName === "input") {
                    it.value = newVal;
                  } else {
                    it.textContent = newVal;
                  }
                }
              );
            }
          });

        // 绑定事件
        document.querySelectorAll("[ng-click]").forEach(it => {
          const bindKey = it.getAttribute("ng-click");
          it.addEventListener("click", e => {
            if (app[bindKey] && typeof app[bindKey] === "function") {
              app[bindKey]();
              app.digest();
            }
          });
        });

        // 双向绑定
        document.querySelectorAll("input[ng-bind]").forEach(it => {
          const bindKey = it.getAttribute("ng-bind");
          it.addEventListener("input", e => {
            app[bindKey] = it.value;
            app.digest();
          });
        });
      }
    </script>
  </body>
</html>
上一篇:AndroidQ 图形系统(2)生产者-消费者模型


下一篇:ORACLE数据库逐步解决ORA-12541、ORA-01034和ORA-27101、ORA-00119和ORA00132的过程