ExtJS 是一种 JavaScript 编写的与后台无关的 Ajax 框架,它提供了可重用的对象和部件. 在简化 Ajax 开发的同时又起到丰富客户端界面的效果.该框架的核心思想是通过 JavaScript 动态创建页面的标记元素,从而使得页面更灵活. 其实 ExtJS 本身并没使用到新技术, 而是在 JavaScript 基础上结合这些设计思想发展过来的.而 ExtJS 事件机制作为ExtJS 架构体系中核心部分 它不仅扩展浏览器 Dom 元素事件, 使其兼容于各大主流浏览器 而且它采用观察者模式的来架构组件的事件机制为组件提供了良好的扩展性.
1 ExtJS 事件机制
什么是事件呢? 事件及事件处理其实就是当用户执行某一个状态或者是当对象执行某一个操作时, 会给哪些关心这个动作的对象发送一个通知. 那些对象监听者接受到通知后会执行相应的操作,针对数据操控行为都可以被看为一个事件, 并以相同的方式来处理,事件常用于图形化的界面中是图形化界面消息通信的一项重要元素
ExtJS 为用户提供了一批标准的组件 当然这些组件支持事件的机制的 这样可以围绕组件的事件进行编程了
ExtJS 框架中存在着大量的事件操作 那些事件所通知的对象不仅是可以看得见控件 而且还可以延伸到非可视的数据层面对象.
1.1 浏览器事件
ExtJS 将事件分为了两种 浏览器事件和自定义事件
浏览器事件 就是传统意义上的鼠标单击 移动等事件 由浏览器根据用户的动作而触发的一类事件与页面元素密切相关.相关的类有 Ext.Element Ext.EventManager ,Ext.EventObject ,Ext.lib.Event, Element 包含了常见的 DOM 方法和属性 它提供了一个快捷的 统一的 跨浏览器的接口 而对于事件的处理 Ext.Element 将这一操作委托给了 Ext.EventManager 由 Ext.EventManager 对页面浏览器事件实施管理 如增加事件处理器 移除事件处理器等操作 至于 Ext.EventObject 则是对原始的浏览器事件进行了封装. 提供给事件处理器一个统一的事件接口.那么 Ext.lib.Event 呢 ?其实 Ext.EventManager 的很多功能都是调用 Ext.lib.Event 来实现的. 它维护着所有的事件处理器
在当前主流的浏览器中主要存在三种事件模型 原始事件模型( original event model) , DOM2 事件模型 ,IE 事件模型 其中原始的事件模型被所有浏览器所支持 ,而 DOM2 中所定义的事件模型目前被除了 IE 以外的所有主流浏览器支持.
1.1.1 原始事件模型
原始事件模型可以通过嵌入处理代码到 HTML 标签和赋值到元素的事件属性中来进行注册事件的处理工作 它和其他两个模型最大的区别在于该模型中没有明确的 event 对象 可以有两种方法将事件处理函数跟特定的事件联系起来
1 在 html 中设置感兴趣的元素的属性
- <a id="test" style="cursor:hand; " href=http://www.yxnu.net onclick="alert('direct:'+id); "this is a test please click me </div>
- <script type="text/javascript">
- // 输入代码
- </script>
这是一个简单的测试 如果想要注册一个事件 最原始的方式就是直接在其 HTML 标签中对应的事件属性中写上可运行的 JS代码 在上面的代码中 给 a 标签的 click 事件编写了处理语句 是直接通过 id 来取到当前标签的属性值 得到处理结果是弹出direct: test 值
2 在 javascript 中设置元素对象的属性 如
docuemnt.getElementById("form1").onsubmite=validateForm;
采用这种方法时应注意的是不能在函数调用的末尾加上括号 是把对函数的引用赋值给对象 而不是把函数的执行结果赋值给对象 这样可以最大程度的降低 js 文件和 html 文件的依赖性 缺点是不够直观 浏览器会根据函数的返回值来决定是否激活元素的默认行为 返回 true 则激活 否则不激活
通过两种方法中的任意一种设置事件处理函数相当于给该元素定义了一个新方法 在事件被触发的时候 在处理函数体内 this关键字指向的是发出该事件的元素。
1.1.2 DOM2 事件模型
DOM2 事件模型参考了 IE 的气泡模型而制定的 它是由 w3c 制定的规范。 在原始模型中事件一旦发生就直接调用事件属性,不存在其它事件传播过程,而在 DOM2 模型中事件有一个特殊的传播过程 ,分为三个阶段:
(1) capturing phase:事件被从 document 一直向下传播到目标元素 在这过程中如果有哪个祖先元素对该事件感兴趣可以注册自己的处理函数
(2) 事件到达目标元素 执行目标元素的事件处理函数
(3) 事件从目标元素上升一直到达 document 虽然所有的事件类型都会经历 1 阶段但是只有部分事件会经历 3 阶段
在整个的事件传播过程中可以通过调用 event.stopPropagation()来停止事件的传播 调用 preventDefault()来阻止浏览器的默认行为
这个事件模型有些复杂 但是它集中事件处理代码方面作用很大 例如 如果希望在<p>元素上注册 onclick 事件 那么可以直接注册在 documnet 上 而在第一或第三阶段来处理该事件 利用 event 的 target 来判断是否是<p>元素
在 DOM2 模型中 document 中的所有元素和 window 对象都实现了 EventTarget 接口 该接口定义了添加和删除事件处理函数的的方法 addEventListener("eventType","handler","true! false");
//eventType 去掉原始模型中的 on 前缀
//handler 的执行在它定义的范围内被执行 没有特殊的执行链
//"true|false" 如果为 true 则在事件传播的第一阶段会执行该处理函数
//为 false 直接在该元素上发生或者在 3 阶段的祖先元素中被执行
removeEventListner("eventType","handler","true! false");
在实现了 DOM2 的浏览器中 为了提供向后兼容性 通过原始模型设置的事件处理函数也会得到一个 event 的引用 可以在函数内部得到并使用 在 IE 中也一样
1.1.3 IE 模型
IE 模型也提供了一个 Event 对象封装了事件的详细信息 但是 IE 不把该对象传入事件处理函数 .由于在任意时刻只会存在一个事件,所以 IE 把它作为全局对象 window 的一个属性 IE 中的事件传播模式对应于 DOM2 的第二和第三阶段 首先执目标元素的处理函数 然后向上传播到达 document,ie 中只能能捕捉鼠标事件 而 DOM2 中可以捕捉所有的事件 IE 中注册和删除事件处理函数的方法也不同于 DOM2
dom2 和 ie 两种事件模型中通用的事件处理函数
function portableEventHandler(event) {
var e = event || window.event;
}
事件处理函数的注册和删除是通过元素的
attachEvent( "eventType","handler")
detachEvent("eventType","handler" )
与 dom2 不同的是 eventType 有 on 前缀, 但是令人费解的是这两个函数是作为全局函数被调用的, 就是说在处理函数的内部this 指代的是 window 对象 通过 setCapture() releaseCapture()捕捉鼠标事件 所有的 document 元素都具有这两个函数 一旦调用了某个元素的 setCapture( )函数 所有后续的鼠标事件都会在上浮之前传到该元素 直到调用了 releaseCapture( ) 注意在浏览器失去焦点 弹出对话框或弹出系统菜单时都会使元素失去捕捉能力 这时会有一个 onlosecapture 事件发生 最常见的调用 setCapture()情况是在 onmousedown 的处理函数中 以捕捉后续的 mousemove 事件.
1.2 自定义事件
这类事件通常与组件相关 并且需要用户根据组件的状态自己触发 ExtJS 的自定义事件主要分为三额步骤 :
1.在类中定义事件名称
2.实例化对象 并在该对象中定义事件的监听函数
3.触发事件
相关的类 Ext.util.Observable Ext.util.Event Observable.js Ext.util.Observable 是所有组件 component 的父类. 它的一切子类都可以获得自定义新事件的能力 只要用户为组件登记了事件. 设置了事件监听器, 那么 Observable 类会在其 events 属性那里保存事件 Observable 给所有的子类提供了一个统一的接口来发布事件以及管理事件. 这一特性对于组件来说是至关重要的. 通过 ExtJS 的自定义事件的机制 可以实现一对多的观察者模式 也可以实现一对一的绑定模式 ,这一点在ExtJS 的开发中是很重要的地位
ExtJS 的组件编程也极度依赖于事件模型 事件模型的最初底层不外乎是浏览器开发商对网页的 DOM 结构 DOM 模型预留的事件监听器接口的 API 使得每一个元素(Element)只要创建完毕之后 就存在一种 无限循环 的机制以等待用户的动作 并根据DOM 元素所发生的动作去触发事件 从语法的表面上 ExtJS 尝试尝试以一种简约的编程风格涵盖主流浏览器的事件模型 好让开发者摆脱异种浏览器代码适应的问题.
2.事件传播
DOM 事件标准定义了两种事件流 这两种事件流有着显著的不同并且可能对你的应用有着相当大的影响 这两种事件流分别是捕获和冒泡 和许多 Web 技术一样 在它们成为标准之前 Netscape 和微软各自不同地实现了它们 Netscape 选择实现了捕获事件流 微软则实现了冒泡事件流 应该值得庆幸的是 W3C 决定组合使用这两种方法 现在大多数新浏览器都遵循这两种事件流方式
冒泡事件流
当事件在某一 DOM 元素被触发时 例如 用户在复选框节点上点击鼠标 事件将跟随着该节点继承自的各个父节点冒泡穿过整个的 DOM 节点层次 直到它遇到依附有该事件类型处理器的节点 这时 该事件是 onclick 事件 在冒泡过程中的任何时候都可以终止事件的冒泡 在遵从 W3C 标准的浏览器里可以通过调用事件对象上的 stopPropagation()方法 在 Internet Explorer 里可以通过设置事件对象的 cancelBubble 属性为 true 如果不停止事件的传播 事件将一直通过 DOM 冒泡直至到达文档的根
捕获事件流
和冒泡事件流不同 在捕获事件流中事件的处理是从 DOM 层次的根开始 并非从触发事件的目标元素开始 事件被从目标元素的所有祖先元素依次往下传递 在这个过程中 事件会被从文档根到事件目标元素之间各个继承派生的元素所捕获 如果事件监听器在被注册时设置了 useCapture 属性为 true 那么它们可以被分派给这期间的任何元素以对事件做出处理 否则 事件会被接着传递给派生元素路径上的下一元素 直至目标元素 事件到达目标元素后 它会接着通过 DOM 节点再进行冒泡