资讯专栏INFORMATION COLUMN

【源码解析】Vue.js的监听实现

freewolf / 1896人阅读

摘要:这段代码出现在解析属性的时候,即调用方法配置的属性。最终是周知订阅者更新,那么上面的数据变更就是发布者。在指令中实例化了,函数负责来更新在解析模板的时候会解析,然后绑定,实例化,这样模板就关联在一起了。

本文地址: http://www.iamaddy.net/2016/1...

一说到监听,当然就离不了设计模式中鼎鼎大名的观察者模式。举个例子,你家后院着火了,可一定要等到烟雾很大火光很亮你才能发现啊,可是当你安装了一个火灾预警器,当发生火灾就立马能够通知到你了。这就是一个典型的观察者模式。当然也还有一些其他变种,比如发布/订阅(publish/subscribe)模式。

我们知道如果要将数据和视图关联起来,在数据变更的时候,同步视图,同理视图变更,数据也发生变化。vue.js是怎么实现这个的呢?下面我们来揭开它的神秘面纱。
demo:


{{ message }}

set: function reactiveSetter(newVal) {
  var value = getter ? getter.call(obj) : val;
  if (newVal === value) {
    return;
  }
  if (setter) {
    setter.call(obj, newVal);
  } else {
    val = newVal;
  }
  childOb = observe(newVal);
  dep.notify();
}

这段代码出现在解析data属性的时候,即调用Object.defineProperty方法配置data的属性。一旦属性发生变化,就notify发送广播。

Dep.prototype.notify = function () {
  // stablize the subscriber list first
  var subs = toArray(this.subs);
  for (var i = 0, l = subs.length; i < l; i++) {
    subs[i].update();
  }
};

notify 最终是周知subscribe(订阅者)更新,那么上面的数据变更就是发布者。
subscribe是Watcher这个类的实例化对象,在实例化的时候,会传入回调函数来执行update,vue弄了一个队列来执行watcher的更新函数,具体可参考源码。

Watcher.prototype.run = function () {
    ……
    if (value !== this.value || (isObject(value) || this.deep) && !this.shallow) {
      ……
      } else {
        this.cb.call(this.vm, value, oldValue);
      }
    }
    this.queued = this.shallow = false;
  }
 };

在Directive(指令)class中实例化了Watcher,_update函数负责来更新

var watcher = this._watcher = new Watcher(this.vm, this.expression, this._update, // callback
      {
        filters: this.filters,
        twoWay: this.twoWay,
        deep: this.deep,
        preProcess: preProcess,
        postProcess: postProcess,
        scope: this._scope
      });

在解析模板的时候会解析Directive,然后绑定,实例化watcher,这样模板-data就关联在一起了。

观察者模式

林林总总的mvc或者mvvm框架基本也都是利用了观察者模式,这个也非常有用,尤其在复杂的系统之中。

利用观察者模式,在典型的ajax应用中,回调的处理逻辑可以不跟请求耦合在一块,这样逻辑上也会更加清晰。如下是一个简单的发布/订阅模式的实现

var PubSub = {};
(function (q) {
    var topics = {}, subUid = -1;
    q.publish = function (topic) {
        if(!topics[topic]){
            return false;
        }

        var subscribers = topics[topic],
            len = subscribers ? subscribers.length : 0;

        while(len--){
            var args = Array.prototype.slice.call(arguments, 1);
            args.unshift(topic);
            subscribers[len].callback.apply(this, args);
        }
        return this;
    };

    q.subscribe = function (topic, callback) {
        if(!topics[topic]){
            topics[topic] = [];
        }

        var subuid = (++subUid).toString();

        topics[topic].push({
            token: subuid,
            callback: callback
        });

        return subuid;
    };

    q.unsubscribe = function (subid) {
        for(var k in topics){
            if(topics[k]){
                for(var i = 0, j = topics[k].length; i < j; i++){
                    if(topics[k][i].token === subid){
                        topics[k].splice(i, 1);
                        return subid;
                    }
                }
            }
        }
        return this;
    };
})(PubSub);

这就是一个简单的订阅发布系统,每注册一个订阅者,其实就是将其回调处理的callback保存在一个字典对象的数组中,字典对象的key值可以随意定义,只要与发布时的key对应起来就好。怎么使用呢?


最后一个将不会打印出来,因为已经取消订阅了。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87764.html

相关文章

  • Vue.js 源码学习笔记

    摘要:实际上,我在看代码的过程中顺手提交了这个,作者眼明手快,当天就进行了修复,现在最新的代码里已经不是这个样子了而且状态机标识由字符串换成了数字常量,解析更准确的同时执行效率也会更高。 最近饶有兴致的又把最新版 Vue.js 的源码学习了一下,觉得真心不错,个人觉得 Vue.js 的代码非常之优雅而且精辟,作者本身可能无 (bu) 意 (xie) 提及这些。那么,就让我来吧:) 程序结构梳...

    darkbaby123 评论0 收藏0
  • Vue.js 源码学习笔记

    摘要:实际上,我在看代码的过程中顺手提交了这个,作者眼明手快,当天就进行了修复,现在最新的代码里已经不是这个样子了而且状态机标识由字符串换成了数字常量,解析更准确的同时执行效率也会更高。 最近饶有兴致的又把最新版 Vue.js 的源码学习了一下,觉得真心不错,个人觉得 Vue.js 的代码非常之优雅而且精辟,作者本身可能无 (bu) 意 (xie) 提及这些。那么,就让我来吧:) 程序结构梳...

    jsdt 评论0 收藏0
  • 太原面经分享:如何在vue面试环节,展示你晋级阿里P6+技术功底?

    摘要:假如你通过阅读源码,掌握了对的实现原理,对生态系统有了充分的认识,那你会在面试环节游刃有余,达到晋级阿里的技术功底,从而提高个人竞争力,面试加分更容易拿。 前言 一年一度紧张刺激的高考开始了,与此同时,我也没闲着,奔走在各大公司的前端面试环节,不断积累着经验,一路升级打怪。 最近两年,太原作为一个准二线城市,各大互联网公司的技术栈也在升级换代,假如你在太原面试前端岗位,而你的技术库里若...

    xiaoqibTn 评论0 收藏0
  • JavaScript 进阶之深入理解数据双向绑定

    摘要:当我们的视图和数据任何一方发生变化的时候,我们希望能够通知对方也更新,这就是所谓的数据双向绑定。返回值返回传入函数的对象,即第一个参数该方法重点是描述,对象里目前存在的属性描述符有两种主要形式数据描述符和存取描述符。 前言 谈起当前前端最热门的 js 框架,必少不了 Vue、React、Angular,对于大多数人来说,我们更多的是在使用框架,对于框架解决痛点背后使用的基本原理往往关注...

    sarva 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<