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

    backbone库学习-Events

    backbone库的框架

    http://www.cnblogs.com/nuysoft/archive/2012/03/19/2404274.html

    我们先从backbone的Events模块开始

    复制代码
    var Events = Backbone.Events ={}
    var eventSplitter = /s+/;
    var eventsApi = function(obj, action, name, rest){}
    var triggerEvents = function(events, args){}
    var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
    _.each(listenMethods, function(implementation, method){}
    Events.bind   = Events.on;
    Events.unbind = Events.off;
    _.extend(Backbone, Events);
    复制代码

    举个例子:

    var m = new Backbone.Model();
        m.on('show',function(){
            alert('show')
        })
    
    m.trigger('show');

    第一步:先实例化model模块,在实例上绑定了all的监听事件。最后调用trigger来触发。

    注意看Events部分代码结构:

    _.extend(Backbone, Events);

    backbone依赖underscore.js库,_.extend是underscore.js库的方法。

    我们来看一下:

    复制代码
    _.extend = function(obj) {
            each(slice.call(arguments, 1), function(source) {
                if (source) {
                    for (var prop in source) {
                        obj[prop] = source[prop];
                    }
                }
            });
            return obj;
        };
    复制代码

    根据以上代码,我们大概知道_.extend(Backbone,Events)的意思了,将Events的成员添加到Backbone。Backbone调用的方法名与Events调用的方法名一致。

    继续看例子

    m.on('show',function(){
            alert('show')
        })

    找到相应源码

    复制代码
    on: function(name, callback, context) {
                if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
                this._events || (this._events = {});//这是一个事件,将实例中设置一个_events属性
                var events = this._events[name] || (this._events[name] = []);//再定义一个events存储this._events[name]
                events.push({callback: callback, context: context, ctx: context || this});//事件序列,往数组里push事件
                return this;
            }
    复制代码

    其中有个eventsApi方法,看下这个方法

    复制代码
    var eventsApi = function(obj, action, name, rest) {
            if (!name) return true;
            // Handle event maps.
            if (typeof name === 'object') {
                for (var key in name) { //遍历object
                    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;
        };
    复制代码

    这相当于递归执行绑定事件。

    例子中执行了

    m.trigger('show');

    我们再来看trigger方法

    复制代码
    trigger: function(name) {
                if (!this._events) return this;//查看_events序列中是否有事件,没有则返回
                var args = slice.call(arguments, 1);//闭包调用slice,获取参数,进入triggerEvents方法
                if (!eventsApi(this, 'trigger', name, args)) return this;//递归绑定
                var events = this._events[name];//从事件序列取出事件,这里同名方法也能取出
                var allEvents = this._events.all;//源码将这里写死,也就是说,如果我们定义的方法名是all的,将默认都执行一次
                if (events) triggerEvents(events, args);
                if (allEvents) triggerEvents(allEvents, arguments);//注意是最后执行
                return this;
            }
    复制代码

    进入triggerEvents方法

    复制代码
    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 m = new Backbone.Model();
        m.on('all',function(){
            alert('show-all')
        })
    m.trigger('show');

    因为name是all,所以this._events['all']是绑定事件的,在trigger中的allEvents也会是有值的,既它将执行all的事件。如果你将例子再修改

    var m = new Backbone.Model();
        m.on('all',function(){
            alert('show-all')
        })
    m.trigger('all');

    那它会弹两次alert的。第一次执行events,第二次执行allevents。

    关于off,移除事件例子:

    var m = new Backbone.Model();
        m.on('show',function(){
            alert('show')
        })
    m.off('show')
    m.trigger('show');

    看一下off方法:

    复制代码
    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;
                }
    
                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 = [];//清空事件序列
                        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;
            }
    复制代码

    想一下,this._events中的事件被删除和清空了,我们再调用trigger方法时,肯定是不能触发绑定事件的。

    再上一个例子:

    复制代码
    var m = new Backbone.Model();  
      
    // 将监听函数绑定到m对象的all事件中  
    m.on('all', function() {  
        alert('all');  
    });  
    // 将监听函数绑定到m对象的自定义事件show中  
    m.on('show', function() {  
        alert('show title');  
    });  
    // 将另一个监听函数绑定到m对象的自定义事件show中  
    m.on('show', function() {  
        alert('show content');  
    });  
    // 将监听函数绑定到m对象的自定义事件hide中  
    m.on('hide', function() {  
        alert('hide');  
    });  
      
    // 触发m对象的show事件和hide事件  
    m.trigger('show');  
    m.trigger('hide');
    复制代码

    思考一下,显示结果。

    简单来看一下,绑定all事件,因为触发all事件是写在trigger方法中,并且是最后执行,所以调用trigger执行完其他方法后,再执行all事件。每一次调用trigger都会执行一遍。下面就依次绑定show和hide方法,其中show方法绑定了两遍,但方法内容不同,backbone允许这样的绑定。不会覆盖。我们来看一下后台的事件序列中的情况。我们取方法名为show的情况看下

    可以看到同名的show方法是两个,trigger执行时,会从数组中依次取出执行,执行顺与定义的顺一致。

    内容不多,时间刚好,以上是我的一点读码体会,如有错误,请指出,大家共通学习。

  • 相关阅读:
    idea初始化配置
    常用网址
    linux改错了profile文件
    获得ip地址[转载]
    java 基本数据类型转换
    log4j配置概要
    HTTP状态码
    HTTP 的请求方式
    10、类和方法
    9、一切都是对象
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3325737.html
Copyright © 2011-2022 走看看