当前位置:Gxlcms > JavaScript > 源码分析Vue.js的监听实现教程

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

时间:2021-07-01 10:21:17 帮助过:3人阅读

前言

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

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

demo:

  1. <script src="../vue.js"> </script>
  2. <div id="app">
  3. <p>
  4. {{ message }}
  5. </p>
  6. <input v-model="message">
  7. </div>
  8. <script type="text/javascript">
  9. new Vue({
  10. el: '#app',
  11. data: {
  12. message: 'Hello Vue.js!'
  13. }
  14. });
  15. </script>
  16. set: function reactiveSetter(newVal) {
  17. var value = getter ? getter.call(obj) : val;
  18. if (newVal === value) {
  19. return;
  20. }
  21. if (setter) {
  22. setter.call(obj, newVal);
  23. } else {
  24. val = newVal;
  25. }
  26. childOb = observe(newVal);
  27. dep.notify();
  28. }

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

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

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

  1. Watcher.prototype.run = function () {
  2. ……
  3. if (value !== this.value || (isObject(value) || this.deep) && !this.shallow) {
  4. ……
  5. } else {
  6. this.cb.call(this.vm, value, oldValue);
  7. }
  8. }
  9. this.queued = this.shallow = false;
  10. }
  11. };

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

  1. var watcher = this._watcher = new Watcher(this.vm, this.expression, this._update, // callback
  2. {
  3. filters: this.filters,
  4. twoWay: this.twoWay,
  5. deep: this.deep,
  6. preProcess: preProcess,
  7. postProcess: postProcess,
  8. scope: this._scope
  9. });

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

图片描述

观察者模式

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

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

  1. var PubSub = {};
  2. (function (q) {
  3. var topics = {}, subUid = -1;
  4. q.publish = function (topic) {
  5. if(!topics[topic]){
  6. return false;
  7. }
  8. var subscribers = topics[topic],
  9. len = subscribers ? subscribers.length : 0;
  10. while(len--){
  11. var args = Array.prototype.slice.call(arguments, 1);
  12. args.unshift(topic);
  13. subscribers[len].callback.apply(this, args);
  14. }
  15. return this;
  16. };
  17. q.subscribe = function (topic, callback) {
  18. if(!topics[topic]){
  19. topics[topic] = [];
  20. }
  21. var subuid = (++subUid).toString();
  22. topics[topic].push({
  23. token: subuid,
  24. callback: callback
  25. });
  26. return subuid;
  27. };
  28. q.unsubscribe = function (subid) {
  29. for(var k in topics){
  30. if(topics[k]){
  31. for(var i = 0, j = topics[k].length; i < j; i++){
  32. if(topics[k][i].token === subid){
  33. topics[k].splice(i, 1);
  34. return subid;
  35. }
  36. }
  37. }
  38. }
  39. return this;
  40. };
  41. })(PubSub);

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

怎么使用呢?

  1. <script>
  2. var messageLogger = function(){
  3. console.log(JSON.stringify(arguments));
  4. };
  5. var subscription = PubSub.subscribe('/newMessage', messageLogger);
  6. // {"0":"/newMessage","1":"hello world"}
  7. PubSub.publish('/newMessage', 'hello world');
  8. // {"0":"/newMessage","1":["test","a","b","c"]}
  9. PubSub.publish('/newMessage', ['test', 'a', 'b', 'c']);
  10. // {"0":"/newMessage","1":{"sender":"hello world","body":"hey man"}}
  11. PubSub.publish('/newMessage', {
  12. sender: 'hello world',
  13. body: 'hey man'
  14. });
  15. PubSub.unsubscribe(subscription);
  16. PubSub.publish('/newMessage', ['test', 'a', 'b', 'c'], 1);
  17. </script>

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

总结

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

人气教程排行