源码分析Vue.js的监听实现教程

 更新时间:2017年04月23日 11:18:30   作者:Addy  
这篇文章主要通过源码分析介绍了Vue.js的监听实现,文中通过示例代码介绍的非常详细,相信对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。

前言

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

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

demo:

<script src="../vue.js"> </script>
<div id="app">
 <p>
 {{ message }}
 </p>
 <input v-model="message">
</div>
<script type="text/javascript">
new Vue({
 el: '#app',
 data: {
 message: 'Hello Vue.js!'
 }
});
</script>




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对应起来就好。

怎么使用呢?

<script>
var messageLogger = function(){
 console.log(JSON.stringify(arguments));
 };

var subscription = PubSub.subscribe('/newMessage', messageLogger);
// {"0":"/newMessage","1":"hello world"}
PubSub.publish('/newMessage', 'hello world');

// {"0":"/newMessage","1":["test","a","b","c"]}
PubSub.publish('/newMessage', ['test', 'a', 'b', 'c']);

// {"0":"/newMessage","1":{"sender":"hello world","body":"hey man"}}
PubSub.publish('/newMessage', {
 sender: 'hello world',
 body: 'hey man'
});

PubSub.unsubscribe(subscription);

PubSub.publish('/newMessage', ['test', 'a', 'b', 'c'], 1);
</script>

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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • 在vue中使用Echarts利用watch做动态数据渲染操作

    在vue中使用Echarts利用watch做动态数据渲染操作

    这篇文章主要介绍了在vue中使用Echarts利用watch做动态数据渲染操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • Vue新玩具VueUse的具体用法

    Vue新玩具VueUse的具体用法

    VueUse 是一个基于 Composition API 的实用函数集合。本文就详细的介绍了VueUse的具体用法,具有一定的参考价值,感兴趣的可以了解一下
    2021-11-11
  • vue项目实现中英文切换的详细步骤

    vue项目实现中英文切换的详细步骤

    这篇文章主要给大家介绍了关于vue项目实现中英文切换的详细步骤,项目中经常有中英文切换的功能,接下来就简单实现以下这个功能,文中通过代码介绍的非常详细,需要的朋友可以参考
    2023-11-11
  • 深入理解vue3中的reactive()

    深入理解vue3中的reactive()

    本文主要介绍了深入理解vue3中的reactive(),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • IDEA创建Vue项目的两种方式总结

    IDEA创建Vue项目的两种方式总结

    这篇文章主要介绍了IDEA创建Vue项目的两种方式总结,具有很好的参考价值,希望对大家有所帮助。
    2023-04-04
  • vue 地图可视化 maptalks 篇实例代码详解

    vue 地图可视化 maptalks 篇实例代码详解

    这篇文章主要介绍了vue 地图可视化 maptalks 篇,本文分步骤通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值 ,需要的朋友可以参考下
    2019-05-05
  • vue2+element-ui新增编辑表格+删除行功能

    vue2+element-ui新增编辑表格+删除行功能

    这篇文章主要介绍了vue2+element-ui新增编辑表格+删除行功能,本文通过示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-07-07
  • Vue项目中使用addRoutes出现问题的解决方法

    Vue项目中使用addRoutes出现问题的解决方法

    大家应该都知道可以通过vue-router官方提供的一个api-->addRoutes可以实现路由添加的功能,事实上就也就实现了用户权限,这篇文章主要给大家介绍了关于Vue项目中使用addRoutes出现问题的解决方法,需要的朋友可以参考下
    2021-08-08
  • 如何基于vue-cli3.0构建功能完善的移动端架子

    如何基于vue-cli3.0构建功能完善的移动端架子

    这篇文章主要介绍了基于vue-cli3.0构建功能完善的移动端架子,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • vue服务端渲染缓存应用详解

    vue服务端渲染缓存应用详解

    vue缓存分为页面缓存、组建缓存、接口缓存,这里我主要说到了页面缓存和组建缓存。接下来通过本文给大家介绍vue服务端渲染缓存应用 ,需要的朋友可以参考下
    2018-09-09

最新评论