zoukankan      html  css  js  c++  java
  • Kendo UI

     在 Kendo 中,基类 Class 第一个重要的派生类就是 Observable, 顾名思义,就是一个可观察的对象,也就是观察者模式的基础。

    对于观察者模式来说,应该有主题和观察者,这里我们讨论的其实是主题,观察者只需要提供一个回调函数,在适当的时候得到回调就可以了。

    对于主题来说,我们应该支持多种观察的目标,如果你使用过 .NET 的事件,这里简直就是将 .NET 的事件轮子重新实现了一下。

    1.事件

    _events 是用来保存注册的事件信息的存储对象,可以在主题上定义多种事件,每个事件就是 _events 上的一个字段,字段的名字就是事件名称,值是一个数组,用来保存注册到这个事件的回调函数。初始化函数中,将这个对象创建出来。

    init: function() {
       this._events = {};
    },

    2. 注册

    bind 函数用来进行注册,既可以使用事件名称,处理器方式,也可以一次性注册多个事件,使用事件名称的数组,对应每个事件的处理函数对象来表示。

    最关键的实际上是这两行。

     events = that._events[eventName] = that._events[eventName] || [];
     events.push(handler);

    这里有一些特殊的处理,就是可以注册仅仅执行一次的处理器。在注册的时候,需要将 one 设置为 true,默认是 undefined,也就是多次的。

    在一次的情况下,会自动将用户注册的处理器另外保存到 original 中,然后创建一个新的处理器进行注册,这个处理器在执行一次之后,自动将自己从处理器列表中删除。

    注册的全部代码

    bind: function(eventName, handlers, one) {
        var that = this,
            idx,
            eventNames = typeof eventName === STRING ? [eventName] : eventName,
            length,
            original,
            handler,
            handlersIsFunction = typeof handlers === FUNCTION,
            events;
    
        if (handlers === undefined) {
            for (idx in eventName) {
                that.bind(idx, eventName[idx]);
            }
            return that;
        }
    
        for (idx = 0, length = eventNames.length; idx < length; idx++) {
            eventName = eventNames[idx];
    
            handler = handlersIsFunction ? handlers : handlers[eventName];
    
            if (handler) {
                if (one) {
                    original = handler;
                    handler = function() {
                        that.unbind(eventName, handler);
                        original.apply(that, arguments);
                    };
                    handler.original = original;
                }
                events = that._events[eventName] = that._events[eventName] || [];
                events.push(handler);
            }
        }
    
        return that;
    },

    3. 取消注册

    对应注册的就是取消注册了。

    unbind 完成取消注册的任务,取消注册的时候,有三种选择

    • 全部取消注册的观察者
    • 将某个时间的观察者取消
    • 或者单个取消

    所以代码更加简单明了。original 就是在一次性事件中保存的原有处理器。

    unbind: function(eventName, handler) {
        var that = this,
            events = that._events[eventName],
            idx;
    
        if (eventName === undefined) {
            that._events = {};
        } else if (events) {
            if (handler) {
                for (idx = events.length - 1; idx >= 0; idx--) {
                    if (events[idx] === handler || events[idx].original === handler) {
                        events.splice(idx, 1);
                    }
                }
            } else {
                that._events[eventName] = [];
            }
        }
    
        return that;
    }

    4. 触发处理

    触发就比较容易了,提供事件的名称,事件的参数就可以了,直接遍历数组中保存的每一个处理器,通过 call 调用将对象自己作为 this 传递到处理器中。

    trigger: function(eventName, e) {
        var that = this,
            events = that._events[eventName],
            idx,
            length;
    
        if (events) {
            e = e || {};
    
            e.sender = that;
    
            e._defaultPrevented = false;
    
            e.preventDefault = preventDefault;
    
            e.isDefaultPrevented = isDefaultPrevented;
    
            events = events.slice();
    
            for (idx = 0, length = events.length; idx < length; idx++) {
                events[idx].call(that, e);
            }
    
            return e._defaultPrevented === true;
        }
    
        return false;
    }

    5. 辅助函数

    额外还提供了两个辅助函数,one 和 first

    one 用来检查注册仅仅执行一次的处理器,你会看到通过直接将 bind 的 one 参数设置为 true 来实现的。

    one: function(eventNames, handlers) {
        return this.bind(eventNames, handlers, true);
    },

    first 用来将处理函数压入调用对象的最前面, unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。

    first: function(eventName, handlers) {
        var that = this,
            idx,
            eventNames = typeof eventName === STRING ? [eventName] : eventName,
            length,
            handler,
            handlersIsFunction = typeof handlers === FUNCTION,
            events;
    
        for (idx = 0, length = eventNames.length; idx < length; idx++) {
            eventName = eventNames[idx];
    
            handler = handlersIsFunction ? handlers : handlers[eventName];
    
            if (handler) {
                events = that._events[eventName] = that._events[eventName] || [];
                events.unshift(handler);
            }
        }
    
        return that;
    },

    6. 全部代码

    全部代码如下:

    var Observable = Class.extend({
        init: function() {
            this._events = {};
        },
    
        bind: function(eventName, handlers, one) {
            var that = this,
                idx,
                eventNames = typeof eventName === STRING ? [eventName] : eventName,
                length,
                original,
                handler,
                handlersIsFunction = typeof handlers === FUNCTION,
                events;
    
            if (handlers === undefined) {
                for (idx in eventName) {
                    that.bind(idx, eventName[idx]);
                }
                return that;
            }
    
            for (idx = 0, length = eventNames.length; idx < length; idx++) {
                eventName = eventNames[idx];
    
                handler = handlersIsFunction ? handlers : handlers[eventName];
    
                if (handler) {
                    if (one) {
                        original = handler;
                        handler = function() {
                            that.unbind(eventName, handler);
                            original.apply(that, arguments);
                        };
                        handler.original = original;
                    }
                    events = that._events[eventName] = that._events[eventName] || [];
                    events.push(handler);
                }
            }
    
            return that;
        },
    
        one: function(eventNames, handlers) {
            return this.bind(eventNames, handlers, true);
        },
    
        first: function(eventName, handlers) {
            var that = this,
                idx,
                eventNames = typeof eventName === STRING ? [eventName] : eventName,
                length,
                handler,
                handlersIsFunction = typeof handlers === FUNCTION,
                events;
    
            for (idx = 0, length = eventNames.length; idx < length; idx++) {
                eventName = eventNames[idx];
    
                handler = handlersIsFunction ? handlers : handlers[eventName];
    
                if (handler) {
                    events = that._events[eventName] = that._events[eventName] || [];
                    events.unshift(handler);
                }
            }
    
            return that;
        },
    
        trigger: function(eventName, e) {
            var that = this,
                events = that._events[eventName],
                idx,
                length;
    
            if (events) {
                e = e || {};
    
                e.sender = that;
    
                e._defaultPrevented = false;
    
                e.preventDefault = preventDefault;
    
                e.isDefaultPrevented = isDefaultPrevented;
    
                events = events.slice();
    
                for (idx = 0, length = events.length; idx < length; idx++) {
                    events[idx].call(that, e);
                }
    
                return e._defaultPrevented === true;
            }
    
            return false;
        },
    
        unbind: function(eventName, handler) {
            var that = this,
                events = that._events[eventName],
                idx;
    
            if (eventName === undefined) {
                that._events = {};
            } else if (events) {
                if (handler) {
                    for (idx = events.length - 1; idx >= 0; idx--) {
                        if (events[idx] === handler || events[idx].original === handler) {
                            events.splice(idx, 1);
                        }
                    }
                } else {
                    that._events[eventName] = [];
                }
            }
    
            return that;
        }
    });

     7. 总结 

    Observable 提供了基本的观察者模式支持。

  • 相关阅读:
    Hdu4547CD操作离线lca
    1036: [ZJOI2008]树的统计Count树链剖分
    light1348Aladdin and the Return Journey树链剖分
    Problem 2082 过路费树链剖分
    2243: [SDOI2011]染色树链剖分
    Poj3237Tree 树链剖分
    Poj2763Housewife Wind树链剖分
    Hdu5087Revenge of LIS II简单dp
    Hdu5088Revenge of Nim II高斯消元
    Bootstrap入门学习笔记(只记录了效果)
  • 原文地址:https://www.cnblogs.com/haogj/p/4975029.html
Copyright © 2011-2022 走看看