zoukankan      html  css  js  c++  java
  • 利用 Proxy API 实现一个简易 MVVM

    vue 3 使用了 proxy api,有些手痒,就弄一个简单的结构玩玩吧。Proxy API 见 MDN Proxy

    效果图

    思路

    依赖收集:Mvvm 初始化时劫持数据,并设置观察者 dep。模仿 vue 结构是在 get 时往观察者 dep 推入被观察者 watcher,然后 set 时让观察者通知所有被观察者开始更新。

    数据响应:这里只是简单在 compiler 里面去扫描了一遍所有带着 v-text 和 v-model 钩子的标签做了处理:定义被观察者 watcher,被观察者的触发函数写上节点 DOM 的更新。

    当然我们知道 vue 的数据响应过程比这个复杂多了,有着虚拟 DOM 和复杂的 diff 算法。

    代码

    <!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 id="app">
        <div  v-text="text1"></div>
        <input type="text"  v-model="text1">
    
        <div  v-text="text2"></div>
        <input type="text" v-model="text2">
      </div>
    
      <script>
        class Watcher {
          constructor(cb) {
            this.cb = cb;
          }
          run() {
            this.cb();
          }
        }
        class Dep {
          constructor() {
            this.subs = [];
            this.target = null;
          }
          notify() {
            this.subs.forEach(item => {
              item.run();
            })
          }
        }
        class Mvvm {
          constructor(data) {
            let that = this;
            this.dep = new Dep();
            this.data = new Proxy(data, {
              get(obj, key, prox) {
                that.dep.target && that.dep.subs.push(that.dep.target);
                return obj.data[key];
              },
              set(obj, key, value, prox) {
                obj.data[key] = value;
                that.dep.notify();
                return true;
              }
            });
            this.compiler();
          }
          compiler() {
            let that = this;
            let app = document.getElementById('app');
            let bindTextNodes = app.querySelectorAll('[v-text]');
            let bindInputNodes = app.querySelectorAll('[v-model]');
    
            bindTextNodes.forEach(bindTextNode => {
              let textModel = bindTextNode.getAttribute('v-text');
              let watcher = new Watcher(function() {
                bindTextNode.innerText = that.data[textModel];
              });
              that.dep.target = watcher;
              bindTextNode.innerText = that.data[textModel];
              this.dep.target = null;
            })
    
            bindInputNodes.forEach(bindInputNode => {
              let inputModel = bindInputNode.getAttribute('v-model');
              let watcher = new Watcher(function() {
                bindInputNode.value = that.data[inputModel];
              });
              this.dep.target = watcher;
              bindInputNode.value = that.data[inputModel];
    
              bindInputNode.addEventListener('input', function(evt) {
                that.data[inputModel] = evt.target.value;
              })
              that.dep.target = null; 
            })
          }
        }
    
        new Mvvm({
          data: {
            text1: '123',
            text2: '789'
          }
        })
      </script>
    </body>
    </html>
    

    为什么时 Proxy 而不是 Object.defineProperty ?

    我们知道 Vue2.0 的反应系统是使用 Object.defineProperty 的 getter 和 setter。 但是,Vue 3 将使用 ES2015 Proxy 作为其观察者机制。 这消除了以前存在的警告,使速度加倍,并节省了一半的内存开销。

    而为什么使用 Proxy 替代 Object.defineProperty?Proxy 可以劫持整个对象,并返回一个新的对象。Proxy 不仅可以代理对象,还可以代理数组,还可以代理动态增加的属性。节省内存,速度加倍。

    为了继续支持 IE11,Vue 3 将发布一个支持旧观察者机制和新 Proxy 版本的构建

  • 相关阅读:
    Selenium2+python自动化55-unittest之装饰器(@classmethod)【转载】
    Selenium2+python自动化54-unittest生成测试报告(HTMLTestRunner)【转载】
    验证码在登录页面的使用
    习课省市区的三级联动(cxselect的使用)
    jira的使用
    springmvc 用拦截器+token防止重复提交
    springMVC发送邮件
    Commons-Collections 集合工具类的使用
    习课的视频播放器 video.js
    习课的redis配置记录
  • 原文地址:https://www.cnblogs.com/everlose/p/13034858.html
Copyright © 2011-2022 走看看