zoukankan      html  css  js  c++  java
  • backbone 学习之Events

    Backbone中的Events对象的主要直接就是实现自定义事件。(熟悉自定义事件的童鞋可以直接忽略此篇了)直接看源码分析:

      // A module that can be mixed in to *any object* in order to provide it with
      // custom events. You may bind with `on` or remove with `off` callback
      // functions to an event; `trigger`-ing an event fires all callbacks in
      // succession.
      //
      //     var object = {};
      //     _.extend(object, Backbone.Events);
      //     object.on('expand', function(){ alert('expanded'); });
      //     object.trigger('expand');
      //
      var Events = Backbone.Events = {
    
        // Bind an event to a `callback` function. Passing `"all"` will bind
        // the callback to all events fired.
        // 绑定事件 name: 事件名 callback:回调函数 context:回调函数执行时的this
        on: function(name, callback, context) {
          // 如果是jquery式的事件绑定('blur change' {blur: .. change: ..}) 或者没有callback 直接返回
          if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
          this._events || (this._events = {});
          var events = this._events[name] || (this._events[name] = []);
          events.push({callback: callback, context: context, ctx: context || this});
          return this;
        },
    
        // Bind an event to only be triggered a single time. After the first time
        // the callback is invoked, it will be removed.
        // 确保只是被触发一次
        once: function(name, callback, context) {
          if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
          var self = this;
          var once = _.once(function() {
            self.off(name, once);
            callback.apply(this, arguments);
          });
          once._callback = callback;
          return this.on(name, once, context);
        },
    
        // Remove one or many callbacks. If `context` is null, removes all
        // callbacks with that function. If `callback` is null, removes all
        // callbacks for the event. If `name` is null, removes all bound
        // callbacks for all events.
        // 移除绑定事件
        off: function(name, callback, context) {
          var retain, ev, events, names, i, l, j, k;
          if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
          if (!name && !callback && !context) {
            this._events = {};
            return this;
          }
    
          // 如果有name, 那么就尝试移除指定的事件 否则话就移除所有的事件
          names = name ? [name] : _.keys(this._events);
          for (i = 0, l = names.length; i < l; i++) {
            name = names[i];
            if (events = this._events[name]) {
              this._events[name] = retain = [];
              // 如果有callback 或者 context 需要判断是否相同
              // 相同则移除 不同的话就不移除
              if (callback || context) {
                for (j = 0, k = events.length; j < k; j++) {
                  ev = events[j];
                  if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
                      (context && context !== ev.context)) {
                    retain.push(ev);
                  }
                }
              }
              // 如果没有任何的监听处理程序 就删除
              if (!retain.length) delete this._events[name];
            }
          }
    
          return this;
        },
    
        // Trigger one or many events, firing all bound callbacks. Callbacks are
        // passed the same arguments as `trigger` is, apart from the event name
        // (unless you're listening on `"all"`, which will cause your callback to
        // receive the true name of the event as the first argument).
        // 触发某类事件 name:事件名 后面可以跟其他参数
        trigger: function(name) {
          if (!this._events) return this;
          var args = slice.call(arguments, 1);
          if (!eventsApi(this, 'trigger', name, args)) return this;
          var events = this._events[name];
          var allEvents = this._events.all;
          if (events) triggerEvents(events, args);
          if (allEvents) triggerEvents(allEvents, arguments);
          return this;
        },
    
        // Tell this object to stop listening to either specific events ... or
        // to every object it's currently listening to.
        // 停止监听对象obj的执行name的callback事件
        stopListening: function(obj, name, callback) {
          var listeners = this._listeners;
          if (!listeners) return this;
          var deleteListener = !name && !callback;
          if (typeof name === 'object') callback = this;
          if (obj) (listeners = {})[obj._listenerId] = obj;
          for (var id in listeners) {
            listeners[id].off(name, callback, this);
            if (deleteListener) delete this._listeners[id];
          }
          return this;
        }
    
      };
    
      // Regular expression used to split event strings.
      var eventSplitter = /\s+/;
    
      // Implement fancy features of the Events API such as multiple event
      // names `"change blur"` and jQuery-style event maps `{change: action}`
      // in terms of the existing API.
      // `"change blur"` `{change: action}` 这两种类型的jquery式事件处理
      var eventsApi = function(obj, action, name, rest) {
        if (!name) return true;
    
        // Handle event maps.
        if (typeof name === 'object') {
          for (var key in name) {
            obj[action].apply(obj, [key, name[key]].concat(rest));
          }
          return false;
        }
    
        // Handle space separated event names.
        if (eventSplitter.test(name)) {
          var names = name.split(eventSplitter);
          for (var i = 0, l = names.length; i < l; i++) {
            obj[action].apply(obj, [names[i]].concat(rest));
          }
          return false;
        }
    
        return true;
      };
    
      // A difficult-to-believe, but optimized internal dispatch function for
      // triggering events. Tries to keep the usual cases speedy (most internal
      // Backbone events have 3 arguments).
      // 方便触发事件时 传给 事件处理函数 的参数问题
      var triggerEvents = function(events, args) {
        var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
        switch (args.length) {
          case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
          case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
          case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
          case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
          default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
        }
      };
    
      var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
    
      // Inversion-of-control versions of `on` and `once`. Tell *this* object to
      // listen to an event in another object ... keeping track of what it's
      // listening to.
      // 告知当前对象监听另一个对象obj的某个事件 用于跟踪obj的事件
      // 也就是当obj的name类型的事件触发的时候,就会执行当前对象
      // 追踪的这个callback
      _.each(listenMethods, function(implementation, method) {
        Events[method] = function(obj, name, callback) {
          var listeners = this._listeners || (this._listeners = {});
          var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
          listeners[id] = obj;
          if (typeof name === 'object') callback = this;
          obj[implementation](name, callback, this);
          return this;
        };
      });
    
      // Aliases for backwards compatibility.
      Events.bind   = Events.on;
      Events.unbind = Events.off;

    欢迎指导、纠错、建议。

  • 相关阅读:
    Unity WebGL MoonSharp崩溃问题
    UISprite(NGUI)扩展 图片镂空
    自动化交易机器人Beta猪
    如何成为一个真正在路上的Linuxer
    课堂里学不到的C与C++那些事(一)
    Android ART运行时与Dalvik虚拟机
    用Dockerfile构建docker image
    论docker中 CMD 与 ENTRYPOINT 的区别
    sshfs远程文件系统挂载
    docker镜像与容器存储结构分析
  • 原文地址:https://www.cnblogs.com/xiaobudiandian/p/Backbone_Events.html
Copyright © 2011-2022 走看看