无码帝 阅读(58) 评论(0)

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执行时,会从数组中依次取出执行,执行顺与定义的顺一致。

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