在 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. 51nod 1211 数独

    数独游戏规则如下:在9 * 9的盘面上有些已知的数字及未知的数字,推理出所有未知的数字,并满足每一行.每一列.每一个粗线宫内的数字均含1-9,不重复.       有些局面存在多个解或无解,这属于不标 ...

  2. android学习笔记九——RatingBar

    RatingBar==>星级评分条 RatingBar和SeekBar十分相似,它们甚至有相同的父类:AbsSeekBar.两者都允许用户通过拖动来改变进度: 两者最大的区别在于RatingBa ...

  3. c/c++多线程编程中最好不要加volatile

    来自https://www.zhihu.com/question/31459750 答主解释说:不能指望volatile能解决多线程竞争问题,除非所用的环境系统不可靠才会为了保险加上volatile, ...

  4. tcp-ip-状态详解(转)

    TCP正常建立和关闭的状态变化     TCP连接的建立可以简单的称为三次握手,而连接的中止则可以叫做 四次握手.   建立连接   在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建 ...

  5. 1. redis简介

    一. redis简介 Redis是一种面向"键/值"对数据类型的内存数据库,可以满足我们对海量数据的读写需求. redis的键只能是字符串,redis的值支持多种数据类型: (1) ...

  6. Codeforces Round #367 (Div. 2) Hard problem

    Hard problem 题意: 有n个字符串,对第i个字符串进行反转操作代价为ci. 要使n个字符串按照字典序从小到大排列,最小的代价是多少. 题解: 反转就是reverse操作,比如说45873反 ...

  7. NeHe OpenGL教程 第三十八课:资源文件

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  8. cmd命令行给main传参数

    int main(int argc, char **argv) { cout << "arguments passed to main() : " << e ...

  9. LR11

    HP LoadRunner Readme for the Windows operating system Software version: 11.00 Publication date: Octo ...

  10. 斑马打印机网卡ZebraNet配置(有线)

    实图: 抽象图: 说明: 1.并口,用于连接斑马打印机一端 2.网络连接状态指示灯 3.打印状态指示灯 4.测试按钮,在连接打印机的情况下,按下此键,会打印出网卡信息. 5.网线接口 按下测试按钮之后 ...