• 技术文章 >web前端 >Vue.js

    一文了解vue中watcher数据双向绑定原理(附代码)

    奋力向前奋力向前2021-08-25 10:16:57转载253

    之前的文章《解析vue中observer数据双向绑定原理(代码分享)》中,给大家了解了vue中observer数据双向绑定原理。下面本篇文章给大家了解vue中watcher数据双向绑定原理,一定的参考价值,有需要的朋友可以参考一下。

    vue数据双向绑定原理,和简单的实现,本文将实现mvvmwatcher

    微信截图_20210823095546.jpg

    1)vue数据双向绑定原理-observer

    2)vue数据双向绑定原理-wather

    3)vue数据双向绑定原理-解析器Complie

    vue数据双向绑定原理,和简单的实现,本文将实现mvvmWatcher

    上面的步骤已经实现了监听器,和订阅器,当属性发生改变,发出通知,那么这个通知是通知谁呢,肯定是订阅者watcher.Watcher订阅者作为ObserverCompile之间通信的桥梁,主要做的事情是:

    1、在自身实例化时往属性订阅器(dep)里面添加自己

    2、自身必须有一个update()方法

    3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则释放自己。

    // Watcher
    function Watcher(vm, exp, cb) {
      this.cb = cb;
      this.$vm = vm;
      this.exp = exp;
      // 此处为了触发属性的getter,从而在dep添加自己,结合Observer更易理解
      this.value = this.get(); // 将自己添加到订阅器的操作
    }
    Watcher.prototype = {
      update: function () {
        this.run(); // 属性值变化收到通知
      },
      run: function () {
        var value = this.get(); // 取到最新值
        var oldVal = this.value;
        if (value !== oldVal) {
          this.value = value;
          this.cb.call(this.$vm, value, oldVal); // 执行Compile中绑定的回调,更新视图
        }
      },
      get: function () {
        Dep.target = this; // 将当前订阅者指向自己, 缓存
        var value = this.$vm[this.exp]; // 强制触发监听的getter,添加自己到属性订阅器中
        Dep.target = null; // 添加完毕,重置释放
        return value;
      },
    };

    订阅者要缓存自己,并且告诉监听器,要把我加到订阅器里面去。所以还要改造下监听器

    function defineReactive(data, key, val) {
      var dep = new Dep()
      observe(val); // 监听子属性
      Object.defineProperty(data, key, {
        ....
        get: function() {
          // 由于需要在闭包内添加watcher,所以可以在Dep定义一个全局target属性,暂存watcher, 添加完移除
          Dep.target && dep.addDep(Dep.target);
          return val;
        },
        ....
      });
    
    }

    实例化Watcher的时候,调用get()方法,通过Dep.target=watcherInstance标记订阅者是当前watcher实例,强行触发属性定义的getter方法,getter方法执行的时候,就会在属性的订阅器dep添加当前watcher实例,从而在属性值有变化的时候watcherInstance就能收到更新通知。

    实现MVVM

    到这儿先将监听器Observer和监听者Watcher连起来,先模拟一些数据,实现简单的数据绑定

    <div id="name"></div>
    <script>
      function Vue(data, el, exp) {
        this.data = data;
        observe(data);
        el.innerHTML = this.data[exp]; // 初始化模板数据的值
        new Watcher(this, exp, function (value) {
          el.innerHTML = value;
        });
        return this;
      }
      var ele = document.querySelector("#name");
      var vue = new Vue(
        {
          name: "hello world",
        },
        ele,
        "name"
      );
      setInterval(function () {
        vue.data.name = "chuchur " + new Date() * 1;
      }, 1000);
    </script>

    这可以看到div的和内容初始为hello world,每隔一秒之后变换为chuchur加时间戳,虽然是实现了,但是与想象的还差很多。是vue.name不是vue.data.name,所以这里需要给Vue实例添加一个属性代理的方法,使访问vm的属性代理为访问vm.data的属性,改造后的代码如下:

    function Vue(options) {
    
      this.$options = options || {};
      this.data = this.$options.data;
      // 属性代理,实现 vm.xxx -> vm.data.xxx
      var self = this;
      Object.keys(this.data).forEach(function(key) {
    
        self.proxy(key); // 绑定代理属性
    
      });
      observe(this.data, this);
      el.innerHTML = this.data[exp]; // 初始化模板数据的值
      new Watcher(this, exp, function(value) {
    
        el.innerHTML = value;
    
      });
      return this;
    
    }
    
    Vue.prototype = {
    
      proxy: function(key) {
        var self = this;
        Object.defineProperty(this, key, {
          enumerable: false,
          configurable: true,
          get: function proxyGetter() {
            return self.data[key];
          },
          set: function proxySetter(newVal) {
            self.data[key] = newVal;
          }
        });
      }
    
    }

    然后就可以通过vue.name,直接改版模板的数据了,下一步就要实现解析器Complie

    [完]

    推荐学习:vue.js教程

    以上就是一文了解vue中watcher数据双向绑定原理(附代码)的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:禅境花园,如有侵犯,请联系admin@php.cn删除
    专题推荐:vue javascript
    上一篇:解析vue中observer数据双向绑定原理(代码分享) 下一篇:浅析vue中complie数据双向绑定原理(代码详解)
    线上培训班

    相关文章推荐

    • 深入浅析vue3中的custom renderer特性• vue如何动态增加css• vue怎么引用css• Vue的响应式原理是什么?• Vue 3.2发布啦,站起来继续学!

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网