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

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

  • 相关阅读:
    leetcode33. Search in Rotated Sorted Array
    pycharm 设置sublime text3 monokai主题
    django class Meta
    leetcode30, Substring With Concatenation Of All Words
    Sublime text3修改tab键为缩进为四个空格,
    sublime text3 python打开图像的问题
    安装上imesupport输入法依然不跟随的解决办法,
    sublime text3 的插件冲突弃用问题,
    sublime text3 BracketHighlighter括号匹配的设置
    windows 下wget的使用
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3325737.html
Copyright © 2011-2022 走看看