• Backbone Events 源码笔记


    用了backbone一段时间了,做一些笔记和总结,看的源码是1.12

    backbone有events,model,collection,histoty,router,view这些模块,其中events是最基础的,其他的模块的prototype全部都扩展了他,所以events是非常重要的,真的很重要,还好代码比较简单,也比较好理解

    这个里面的代码是从backbone里面剥离出来,然后一点一点研究和调试出来的,可以单独运行,依赖underscore

      1     (function(){
      2         this.Backbone = {};
      3         var array = [];
      4         var slice = array.slice;
      5         // Regular expression used to split event strings.
      6         //劈开eventsApi函数里面传入name,如果name是带空格的字符串
      7         var eventSplitter = /s+/;
      8 
      9   // Implement fancy features of the Events API such as multiple event
     10   // names `"change blur"` and jQuery-style event maps `{change: action}`
     11   // in terms of the existing API.
     12         //如果传入的name(这个对应绑定 删除 触发 监听的事件名)为obj 或者是带空格的字符串,则批量进行相关的操作
     13         var eventsApi = function(obj, action, name, rest) {
     14             if (!name) return true;
     15 
     16             // Handle event maps.
     17             if (typeof name === 'object') {
     18                 for (var key in name) {
     19                     obj[action].apply(obj, [key, name[key]].concat(rest));
     20                 }
     21                 return false;
     22             }
     23 
     24             // Handle space separated event names.
     25             if (eventSplitter.test(name)) {
     26                 var names = name.split(eventSplitter);
     27                 for (var i = 0, length = names.length; i < length; i++) {
     28                     obj[action].apply(obj, [names[i]].concat(rest));
     29                 }
     30                 return false;
     31             }
     32 
     33             return true;
     34         };
     35 
     36 
     37 
     38         var Events = Backbone.Events = {
     39             // Bind an event to a `callback` function. Passing `"all"` will bind
     40             // the callback to all events fired.
     41             // 参数的传入为  事件名, 回调, 回调里面this指向的对象
     42             on: function(name, callback, context) {
     43                 if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
     44                 //对象内部生成一个_events对象 key对应事件名, value为一个数组,里面添加相关的回调函数
     45                 this._events || (this._events = {});
     46                 var events = this._events[name] || (this._events[name] = []);
     47                 //第3个和第4个参数,表示回调函数触发的是偶, 函数里面this的指向
     48                 events.push({callback: callback, context: context, ctx: context || this});
     49                 return this;
     50             },
     51             // Bind an event to only be triggered a single time. After the first time
     52             // the callback is invoked, it will be removed.
     53             //  跟on一样的入参 ,他只会执行一次
     54             once: function(name, callback, context) {
     55                 if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
     56                 var self = this;
     57                 //真正绑定进_.events的事故once 而不是callback,当once执行完一次后,就从_events上面删除掉了
     58                 var once = _.once(function() {
     59                     self.off(name, once);
     60                     callback.apply(this, arguments);
     61                 });
     62                 once._callback = callback;
     63                 return this.on(name, once, context);
     64             },
     65 
     66             // Trigger one or many events, firing all bound callbacks. Callbacks are
     67             // passed the same arguments as `trigger` is, apart from the event name
     68             // (unless you're listening on `"all"`, which will cause your callback to
     69             // receive the true name of the event as the first argument).
     70             trigger: function(name) {
     71                 if (!this._events) return this;
     72                 var args = slice.call(arguments, 1);
     73                 if (!eventsApi(this, 'trigger', name, args)) return this;
     74                 var events = this._events[name];
     75                 var allEvents = this._events.all;
     76                 //通过name 找到对应的回调数组  依次执行里面的回调
     77                 if (events) triggerEvents(events, args);
     78                 //查看是否绑定了all事件 如果绑定也会出阿发
     79                 if (allEvents) triggerEvents(allEvents, arguments);
     80                 return this;
     81             },
     82 
     83             // Remove one or many callbacks. If `context` is null, removes all
     84             // callbacks with that function. If `callback` is null, removes all
     85             // callbacks for the event. If `name` is null, removes all bound
     86             // callbacks for all events.
     87             off: function(name, callback, context) {
     88                 if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
     89 
     90                 // Remove all callbacks for all events.
     91                 //如果参数不存在 就移除所有的事件
     92                 if (!name && !callback && !context) {
     93                     this._events = void 0;
     94                     return this;
     95                 }
     96 
     97                 var names = name ? [name] : _.keys(this._events);
     98                 for (var i = 0, length = names.length; i < length; i++) {
     99                     name = names[i];
    100 
    101                     // Bail out if there are no events stored.
    102                     var events = this._events[name];
    103                     if (!events) continue;
    104 
    105                     // Remove all callbacks for this event.
    106                     //如果只传递name这一个参数 就删除name对应的整个数组
    107                     if (!callback && !context) {
    108                         delete this._events[name];
    109                         continue;
    110                     }
    111 
    112                     // Find any remaining events.
    113                     //
    114                     //如果如果传递了第2个参数  只删除_events[name]里面对应的callback
    115                     //如果传递了第2个参数,第3个参数,还要判断_events[name]里面的callback是否等于第2个参数,context是否等于第3个参数
    116                     //把那么不符合条件的用remaining保存起来
    117                     //然后用this._events[name] = remaining替换掉之前的
    118                     var remaining = [];
    119                     for (var j = 0, k = events.length; j < k; j++) {
    120                         var event = events[j];
    121                         if (
    122                             callback && callback !== event.callback &&
    123                             callback !== event.callback._callback ||
    124                             context && context !== event.context
    125                         ) {
    126                             remaining.push(event);
    127                         }
    128                     }
    129 
    130                     // Replace events if there are any remaining.  Otherwise, clean up.
    131                     if (remaining.length) {
    132                         this._events[name] = remaining;
    133                     } else {
    134                         delete this._events[name];
    135                     }
    136                 }
    137 
    138               return this;
    139             },
    140             // Tell this object to stop listening to either specific events ... or
    141             // to every object it's currently listening to.
    142             stopListening: function(obj, name, callback) {
    143                 var listeningTo = this._listeningTo;
    144                 if (!listeningTo) return this;
    145                 var remove = !name && !callback;
    146                 if (!callback && typeof name === 'object') callback = this;
    147                 if (obj) (listeningTo = {})[obj._listenId] = obj;
    148                 for (var id in listeningTo) {
    149                     obj = listeningTo[id];
    150                     obj.off(name, callback, this);
    151                     if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id];
    152                 }
    153                 return this;
    154             }            
    155         }
    156 
    157         var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
    158 
    159         // Inversion-of-control versions of `on` and `once`. Tell *this* object to
    160         // listen to an event in another object ... keeping track of what it's
    161         // listening to.
    162         //                                   on   listenTo
    163         _.each(listenMethods, function(implementation, method) {
    164             Events[method] = function(obj, name, callback) {
    165                 //obj  为被监听的对象  
    166                 //name 为被监听的事件名
    167                 // callback 是obj触发了name事件后, 别监听到了 然后执行的回调                
    168                 var listeningTo = this._listeningTo || (this._listeningTo = {});
    169                 var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
    170                 //给监听对象添加一个_listeningTo的属性 它的值是一个对象key为_listenId value为被监听的对象  
    171                 //被监听对象添加一个_listenId的属性    它的值为_listenId
    172                 listeningTo[id] = obj;
    173 
    174                 if (!callback && typeof name === 'object') callback = this;
    175                 obj[implementation](name, callback, this);
    176                 return this;
    177             };
    178         });        
    179 
    180         // A difficult-to-believe, but optimized internal dispatch function for
    181         // triggering events. Tries to keep the usual cases speedy (most internal
    182         // Backbone events have 3 arguments).
    183         //批量处理_events里面的回调事件的东西
    184         //参数小于等于3个用call 大于3个用apply  为毛会这样
    185         var triggerEvents = function(events, args) {
    186             var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
    187             switch (args.length) {
    188                 case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
    189                 case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
    190                 case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
    191                 case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
    192                 default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
    193             }
    194         };        
    195     })();
    View Code

    Backbone.Events

    Events主要就是对object进行绑定,触发,删除,监听,它有以下一些方法

    on bind 绑定事件

    trigger 触发绑定事件

    off unbind 移除绑定事件

    listenTo 监听对象

    stopListening 停止监听

    on    object.on(event, callback, [context])

    绑定callback函数到object对象。 当事件触发时执行回调函数callback。第一个参数是事件名,第2个参数是绑定的事件  第3个参数是一个对象,callback里面如果有this,则this指向第3个参数,如果没有传递第3个参数则callback里面的this指向object本身

    当绑定上一个事件的时候,该object会产生一个_events的属性,该属性是一个object类型,key对应的是事件名,value对应的是一个数组,数组里面放的是所有的回调事件

    当触发一个事件的时候,它会遍历_.events,根据传递的事件名,查找相关的回调事件,然后执行。如果绑定了all,则只要调用了trigger,就会调用all下面的所有的回调

    一些例子

    一个object可以绑定多个事件,同一个事件可以有多个回调

                var test = {};
                _.extend(test,Backbone.Events);
                test.on("a",function(){alert(1)}); 
                test.on("a",function(){alert(11)});
                test.on("b",function(){alert(2)});
                test.trigger("a");
                test.trigger("b");
           //test绑定了2个事件a,b  a绑定了2个回调函数

    obj可以批量绑定事件,就是第一个参数是个对象

                var obj = {c:1}
                var test={};
                _.extend(test,Backbone.Events);
                test.on({
                    "a" : function(){alert(1111)},
                    "b" : function(){alert(this.c)}
                },obj);
                test.trigger("b") //弹出1
                //可以一次绑定2个事件a,b 传入的第3个参数是个obj,所以回调执行的时候this指向obj

    如果指定绑定事件名为all,触发任何绑定事件的时候都会触发该事件

                var test = {};
                _.extend(test,Backbone.Events);
                test.on("a",function(){alert(1)});
                test.on("all",function(){alert(111)});
                test.trigger("a"); 
                //触发a事件  也会自动触发all事件

    once    object.on(event, callback, [context])

    绑定callback函数到object对象。 当事件触发时执行回调函数callback。 第3个参数是一个对象,callback里面如果有this,则this指向第3个参数。

    该绑定事件只能触发一次,然后就会被移除掉

                var test = {};
                _.extend(test,Backbone.Events);  
                test.once("a",function(){alert(1)});
                console.log(test);  //test._events里面是有a属性的
                test.trigger("a");
                console.log(test)  //test._events里面的a属性就被删除掉了
                test.trigger("a"); 

    trigger    object.trigger(event, [*args])

    通过事件名触发对应的回调函数。events后面的参数作为参数传入回调事件里面

                var test = {};
                _.extend(test,Backbone.Events);  
                test.on("a",function(a){alert(a)});
                test.on("a",function(a,b){alert(a+b)}); 
                test.on("a",function(a,b,c){alert(a+b+c)});
                test.trigger("a",1,2,3) 
                //依次弹出1,3,6

    off    object.off([event], [callback], [context])

    从object中删除以前绑定的回调函数

    第一个参数是事件名

    第2个参数是指定的函数,如果传了,就只删除绑定在object上的该函数,如果没传,则移除所有的函数

    第3个参数是指定对象,如果绑定的时候调用回调指定了对象,删除的时候也要把该对象带上

    如果调用off的时候不传递参数,则删除所有的绑定事件

    var test = {};
    _.extend(test,Backbone.Events);  
    test.on("a",function(){alert(1)})
    test.on("b",function(){alert(1)})
    console.log(test._events)
    test.off()
    console.log(test._events)
    //删除后test._events就是空的了

    如果指定了删除的事件名,并且传递了第2个参数,而且第2个参数是就是传入的回调的事件,则只删除该指定了回调函数

    var test = {};
    _.extend(test,Backbone.Events); 
    var aFun = function(){alert(1)}
    test.on("a",aFun )
    test.on("a",function(){alert(1)})
    console.log(test._events);
    test.off("a",aFun)
    console.log(test._events);
    //只删除了第二个参数指定的回调函数

    listenTo    object.listenTo(other, event, callback)

    object监听other对象上的指定的方法名上(比如a),如果other触发a,则也会触发监听的回调(callback)

    当一个对象监听其他对象的事件名的时候(比如a,b,2个对象,b绑定haha事件,a监听b的haha事件),a对象会生成_listeningTo的对象,根据_.uniqueId("l")生成的值来做key,value则是b这个对象了。b对象则会生成一个属性_listenId,他的值就是前面_.uniqueId("l")生成的值, 然后如果传入了监听事件的回调函数 再b._events.haha的回调数组中加入该函数,当b触发haha的时候也就会触发该函数了。

    listenTo还是很重要的,比如一个view,初始化的时候就去listento一个model,当model,的时候就会自动通知view去渲染页面

    第一个参数是要监听的对象,

    第二个参数是需要监听的事件名

    第三个参数是当被监听者处罚了该事件,执行的回调

    var test = {};
    var other = {};
    _.extend(test,Backbone.Events);
    _.extend(other,Backbone.Events); 
    other.on("a",function(){alert(1)})
    other.on("a",function(){alert(2)})
    test.listenTo(other,"a",function(){alert("test")})
    other.trigger("a")
    //test监听other,当other触发a时,先执行完ohter自己绑定的回调,在执行监听回调
  • 相关阅读:
    发现程序bug思路
    streambase log(log4j和logback)
    streambase service 变为 window service启动
    机器学习-chapter1机器学习的生态系统
    eoe推荐的优秀博客
    Android Service 服务(一)—— Service .
    android startActivityForResult(Intent intent, int requestCode) 整理与总结! .
    Android Intent详解
    隐式Intent实例
    Android中的距离单位
  • 原文地址:https://www.cnblogs.com/wtcsy/p/3826307.html
Copyright © 2020-2023  润新知