在 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 提供了基本的观察者模式支持。

Kendo UI - Observable的更多相关文章

  1. JQuery Kendo UI使用技巧总结

    Kendo UI开发总结 By Gloomyfish on 2013-04-25 在Grid中支持分页刷新:            scrollable: {virtual : true }, 在Gr ...

  2. Kendo UI开发教程(16): Kendo MVVM 数据绑定(五) Events

    本篇和Kendo UI开发教程(14): Kendo MVVM 数据绑定(三) Click类似,为事件绑定的一般形式.Events绑定支持将ViewModel的方法绑定到DOM元素的事件处理(如鼠标事 ...

  3. [转]Upgrading to Async with Entity Framework, MVC, OData AsyncEntitySetController, Kendo UI, Glimpse & Generic Unit of Work Repository Framework v2.0

    本文转自:http://www.tuicool.com/articles/BBVr6z Thanks to everyone for allowing us to give back to the . ...

  4. Kendo UI 单页面应用(三) View

    Kendo UI 单页面应用(三) View view 为屏幕上某个可视部分,可以处理用户事件. View 可以通过 HTML 创建或是通过 script 元素.缺省情况下 View 将其所包含的内容 ...

  5. Web UI开发推荐!Kendo UI for jQuery自定义小部件——使用MVVM

    Kendo UI for jQuery最新试用版下载 Kendo UI目前最新提供Kendo UI for jQuery.Kendo UI for Angular.Kendo UI Support f ...

  6. Kendo UI for jQuery使用教程:使用MVVM初始化(二)

    [Kendo UI for jQuery最新试用版下载] Kendo UI目前最新提供Kendo UI for jQuery.Kendo UI for Angular.Kendo UI Support ...

  7. kendo ui 实现MVVM

    MVVM                    model----view model----model 实现页面和model之间的动态绑定 grid 支持 events  source  visib ...

  8. Kendo UI Grid 使用总结

    Kendo UI Grid控件的功能强大,这里将常用的一些功能总结一下. Kendo UI Grid 固定列 在使用Gird控件显示数据时,如果数据列过多,会出现横向滚动条,很多情况下,我们希望某些列 ...

  9. kendo ui简介

    Kendo UI Web包含所有创建高速HTML5 web app的必备元素:UI组件.数据源.验证.一个MVVM框架.主题.模板等等. 移动HTML5带UI的开发框架层出不穷,常见的有Sencha ...

随机推荐

  1. startActivityForResult用法详解

    一.如果想在Activity中得到新打开Activity 关闭后返回的数据,需要使用系统提供的startActivityForResult(Intent intent, int requestCode ...

  2. mootools upgrate from 1.2 to 1.3 or 1.4

    Update from 1.2 to 1.3 lorenzos edited this page on 8 Jul 2011 · 2 revisions Pages 19 Home Home Chan ...

  3. Python 模块学习:re模块

    今天学习了Python中有关正则表达式的知识.关于正则表达式的语法,不作过多解释,网上有许多学习的资料.这里主要介绍Python中常用的正则表达式处理函数. 方法/属性 作用 match() 决定 R ...

  4. C# TextBox中只允许输入数字的方法

    1.在Winform(C#)中要实现限制Textbox只能输入数字,一般的做法就是在按键事件中处理, 判断keychar的值.限制只能输入数字,小数点,Backspace,del这几个键.数字0-9所 ...

  5. 黄聪:C#图像处理(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果) (转)

    一.各种旋转.改变大小 注意:先要添加画图相关的using引用. //向右旋转图像90°代码如下:private void Form1_Paint(object sender, System.Wind ...

  6. JQuery 常用方法基础教程

    本文转自(http://www.cnblogs.com/Leo_wl/archive/2010/06/22/1762401.html) 对于学习使用jquery 的朋友,能用的到,简单的了解下jque ...

  7. BIP_开发案例02_BI Publisher中复杂案例实现代码(案例)

    2014-12-27 Created By BaoXinjian

  8. 大神:python怎么爬取js的页面

    大神:python怎么爬取js的页面 可以试试抓包看看它请求了哪些东西, 很多时候可以绕过网页直接请求后面的API 实在不行就上 selenium (selenium大法好) selenium和pha ...

  9. C语言小技巧

    /* 求阶乘时设置最大调用层数,防止栈占满 当从函数进入另一个函数时当前函数的内容会入栈,另一个函数调用完时在出栈 */ int factorial(int n, int level) { //pri ...

  10. CLR via C#笔记

    第一部分 CLR基础 CLR和JIT “运行时”如何解析类型引用 第二部分 设计类型 使用C#的is和as操作符来转型 运行时的相互联系 基元类型.引用类型和值类型 值类型的装箱和拆箱 哈希码 dyn ...