- 浏览: 321546 次
- 性别:
文章分类
最新评论
-
i042416:
分析在哪?
angular分析 -
何盆盆:
你好,请问您这是Extjs3还是Extjs4
ExtJs源码分析与学习—ExtJs事件机制(一) -
124753561:
引用引用引用引用引用[u][u][u][u][i][i][i] ...
Subvision SVN 服务端与客户端的安装 -
谷超:
请问一下例子中itext是什么版本的?
利用iText生成word文档例子参考 -
geosmart:
正好要用到执行字符串中方法,学习了
java中利用反射机制实现调用给定为字符串的方法名
一、 0 级 DOM 上的事件和 2 级 DOM 事件机制
0 级 DOM 上的事件又称原始事件模型,所有的浏览器都支持他,而且是通用的。 2 级 DOM 事件机制又为标准事件模型,除了 ie 其他浏览器都支持( ie9 也支持), ie 虽然大部分与标准事件模型一样,但有自己专有的事件模型,因此开发人员要实现标准事件模型必须为 IE 写特定的代码,这给程序员增加了负担。
原始事件模型
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>浏览器0级DOM上的事件</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> </head> <body> <input type="button" value = "点击我" id = "btn"> </body> </html> <script type="text/javascript"> <!-- var method1 = function(){alert(1)}; var method2 = function(){alert(2)}; var method3 = function(){alert(3)}; document.getElementById("btn").onclick = method1; document.getElementById("btn").onclick = method2; document.getElementById("btn").onclick = method3; //--> </script>
以上书写在各浏览器中都是兼容的,但只有 medhot3 被执行,即同一个对象同一类型的事件只能注册一个处理函数,要想实现注册多个处理函数,需要利用 2 级 DOM 事件机制。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>浏览器2级DOM事件机制</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> </head> <body> <input type="button" value = "点击我" id = "btn"> </body> </html> <script type="text/javascript"> <!-- var method1 = function(){alert(1)}; var method2 = function(){alert(2)}; var method3 = function(){alert(3)}; //执行顺序为method1->method2->method3 //标准事件模型 var btn1Obj = document.getElementById("btn"); btn1Obj.addEventListener("click",method1,false); btn1Obj.addEventListener("click",method2,false); btn1Obj.addEventListener("click",method3,false); //执行顺序为method3->method2->method1 //IE事件模型 var btn1Obj = document.getElementById("btn"); btn1Obj.attachEvent("onclick",method1); btn1Obj.attachEvent("onclick",method2); btn1Obj.attachEvent("onclick",method3); //--> </script>
从运行结果来看, ie 和 firefox 下执行的顺序是不一样的
二、2级DOM事件模型事件的注册与删除
element.addEventListener(eventType,fn,useCapture); // 注册事件
element.removeEventListener(eventType,fn, useCapture);// 删除事件
可以用 addEventListener() 给同一个对象同一类型的事件注册多个处理函数,但是如果在同一元素上多次注册了一个处理函数,那么第一次注册后的所有注册都将被忽略,但删除该注册函数(调用 removeEventListener() )后可以再重新注册该函数。需要注意的是删除事件, useCapture 的值必须要跟注册时保持一致
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>浏览器事件机制——注册和删除事件</title> <style> div {border:1px solid blue;} div#div1 {padding:40px;background-color:#aaaaaa;} div#div2 {padding:40px;background-color:#bbbbbb;} div#div3 {padding:40px;background-color:#cccccc;} </style> </head> <body> <div id="div1" style="width:100px;height:100px;" > 我是老大, 点击我添加老三的click事件 </div> <br/> <div id="div2" style="width:100px;height:110px;" > 我是老二, 点击我删除老三的click事件 </div> <br/> <div id="div3" style="width:100px;height:100px;" > 我是老三,是否有click事件,老大老二说了算,呵呵 </div> <script> function click1() { alert("I am div1,add div3 event"); if(window.addEventListener){ div3.addEventListener("click", click3, false); }else if (window.attachEvent){ div3.attachEvent("onclick", click3); } } function click2() { alert("I am div2,remove div3 event"); if(window.addEventListener){ div3.removeEventListener("click", click3, false); }else if (window.attachEvent){ div3.detachEvent("onclick", click3); } } function click3() { alert("I am div3"); } var div1 = document.getElementById("div1"); var div2 = document.getElementById("div2"); var div3 = document.getElementById("div3"); if(window.addEventListener){ div1.addEventListener("click", click1, false); div2.addEventListener("click", click2, false); }else if (window.attachEvent){ div1.attachEvent("onclick", click1); div2.attachEvent("onclick", click2); } </script> </body> </html>
三、2级DOM事件冒泡模型(Bubble Model)
在2级DOM事件模型中,事件传播分三个阶段进行,即捕获阶段(capturing)、目标阶段和冒泡阶段(bubbling)。在捕获阶段,事件从Document对象沿着文档树向下传播给目标节点,如果目标的任何一个祖先(不是目标本身)专门注册了捕获事件句柄,那么在事件传播过程中,就会运行这些句柄,在冒泡阶段,事件将从目标元素向上传播回或气泡回Document对象的文档层次。虽然所有事件都受事件传播的捕获阶段的支配,但并非所有类型的事件都起泡。
在注册事件时,useCapture参数确定侦听器是运行于捕获阶段、目标阶段还是冒泡阶段。 如果将 useCapture 设置为 true,则侦听器只在捕获阶段处理事件,而不在目标或冒泡阶段 处理事件。 如果useCapture 为 false,则侦听器只在目标或冒泡阶段处理事件。 要在所有三个阶段都侦听事件,需调用两次 addEventListener,一次将 useCapture 设置为 true,第二次再将useCapture 设置为 false。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>浏览器事件机制——冒泡处理</title> <style> div {border:1px solid blue;} div#divGrandpa {padding:40px;background-color:#aaaaaa;} div#divFather {padding:40px;background-color:#bbbbbb;} div#divSon {padding:40px;background-color:#cccccc;} </style> </head> <body> <div id="divGrandpa" style="width:300px;height:200px;" > <div id="divFather" style="width:200px;height:120px;" > <div id="divSon" style="width:100px;height:40px;" > 点击我 </div> </div> </div> <script> function showSon() { alert("I am son"); } function showFather() { alert("I am father"); } function showGrandpa() { alert("I am Grandpa"); } var grandpa = document.getElementById("divGrandpa"); var father = document.getElementById("divFather"); var son = document.getElementById("divSon"); if(window.addEventListener){ grandpa.addEventListener("click", showGrandpa, false); father.addEventListener("click", showFather, false); son.addEventListener("click", showSon, false); }else if (window.attachEvent){ grandpa.attachEvent("onclick", showGrandpa); father.attachEvent("onclick", showFather); son.attachEvent("onclick", showSon); } </script> </body> </html>
从运行结果来看,对于ie,在ie(ie8之前的版本,包括ie8)中当点击son节点时,会分别弹出I am son、I am father和I am Grandpa,即事件最先被底层的结点触发,再逐渐上传,直到最外层的结点,冒泡方式为儿子——>父亲的模式;在Firefox等支持标准事件模型的浏览器中,跟addEventListener的Capture参数有关,当设置为true时,为捕获模式,事件会从最顶层的结点往下传输,即 父亲——>儿子的传播模式。当设为false(默认值)时,则会按冒泡模式传递事件。另外由于ie9即支持window.attachEvent,又支持window.addEventListener,所以会根据代码的书写来运行其效果的。
四、如何停止事件的传递
在IE浏览器中可以调用以下代码
event.cancelBubble = true;
在Firefox等遵循W3C规范的浏览器中,可以调用以下代码
e.stopPropagation();
调用以上代码后可以终止事件在传播过程的捕获、目标处理或起泡阶段进一步传播。调用该方法后,该节点上处理该事件的处理程序将被调用,事件不再被分派到其他节点(即不再进一步传播)。
该方法(属性)将停止事件的传播,阻止它被分派到其他 Document 节点。在事件传播的任何阶段都可以调用它。注意,虽然该方法不能阻止同一个 Document 节点上的其他事件句柄被调用,但是它可以阻止把事件分派到其他节点。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>浏览器事件机制——停止事件的进一步传递</title> <style> div {border:1px solid blue;} div#divGrandpa {padding:40px;background-color:#aaaaaa;} div#divFather {padding:40px;background-color:#bbbbbb;} div#divSon {padding:40px;background-color:#cccccc;} </style> </head> <body> <div id="divGrandpa" style="width:300px;height:200px;" > <div id="divFather" style="width:200px;height:120px;" > <div id="divSon" style="width:100px;height:40px;" > 点击我 </div> </div> </div> <script> function showSon(e) { alert("I am son"); } function showFather(e) { //IE把event对象作为window对象的一个属性,而W3C把event对象作为处理程序的一个参数 e = e || event; if(e.stopPropagation){ e.stopPropagation(); }else{ e.cancelBubble = true; } alert("I am father"); } function showGrandpa(e) { alert("I am Grandpa"); } var grandpa = document.getElementById("divGrandpa"); var father = document.getElementById("divFather"); var son = document.getElementById("divSon"); if(window.addEventListener){ grandpa.addEventListener("click", showGrandpa, false); father.addEventListener("click", showFather, false); son.addEventListener("click", showSon, false); }else if (window.attachEvent){ grandpa.attachEvent("onclick", showGrandpa); father.attachEvent("onclick", showFather); son.attachEvent("onclick", showSon); } </script> </body> </html>
以上代码,把useCapture 设为false后,是在冒泡的时候传播事件。当点击son节点时,先执行son注册的事件,再执行father注册的事件,此时该事件中阻止了事件的向上传播,故grandpa注册的事件被阻止。如果把useCapture 设为true后,是在捕获阶段传播事件。当点击son节点时,是先执行grandpa注册的事件,再执行father注册的事件,此时该事件函数中阻止了事件的传播,故son节点注册的事件不会被执行。
五、自定义事件
1、不带参数事件处理,也是最简单的事件设计模式
最简单的一种模式是将一个类的方法成员定义为事件,通常是一个空函数,当程序需要处理该事件时,再进行扩充该事件接口。比如:
function Class1(){ //构造函数 } Class1.prototype = { show : function(){ this.onShow();//触发onShow事件 }, onShow : function(){}//定义事件接口 } //创建class1实例 var obj = new Class1(); //创建obj的onShow事件处理程序 obj.onShow = function(){ alert('onshow event'); } //调用obj的show方法 obj.show();
以上实现,每个事件接口仅能绑定1个事件处理程序
2、给事件处理程序传递参数
//将有参数的函数封装为无参数的函数 function createFunction(obj, strFn){ obj = obj || window; var args = []; for(var i = 2; i < arguments.length; i++){ args.push(arguments[i]); } return function(){ //该语句相当于obj[strFn](args[0],args[1],...); obj[strFn].apply(obj,args); } } //定义类 Class1 function Class1(){ //构造函数 } Class1.prototype = { show : function(){ this.onShow();//触发onShow事件 }, onShow : function(){}//定义事件接口 } //创建class1实例 var obj = new Class1(); //创建obj的onShow事件处理程序 function objOnShow(userName){ alert('hello, ' + userName); } var userName = 'xiaowang'; //绑定obj的onShow事件 obj.onShow = createFunction(null,'objOnShow',userName); //调用obj的show方法 obj.show();
在以上代码中,将变量userName作为参数传递给了objOnShow事件处理程序。事实上,obj.onShow 得到的事件处理程序并不是objOnShow,而是由createFunction返回的一个无参函数
3、自定义事件支持多绑定
//定义类 Class1 function Class1(){ //构造函数 } Class1.prototype = { show : function(){ //如果有事件绑定则循环onshow数组,触发该事件 if(this.onshow){ for(var i = 0, len = this.onshow.length; i < len; i++){ this.onshow[i]();//调用事件处理程序 } } }, addEventOnShow : function (_eHandler){ this.onshow = this.onshow || [];//用数组存储绑定的事件处理程序引用 this.onshow.push(_eHandler); } } //创建class1实例 var obj = new Class1(); //事件一 function onShow1(){ alert('event1'); } //事件二 function onShow2(){ alert('event2'); } //绑定事件 obj.addEventOnShow(onShow1); obj.addEventOnShow(onShow2); //调用obj的show方法 obj.show();
4、自定义事件支持带参数的多绑定
//将有参数的函数封装为无参数的函数 function createFunction(obj, strFn){ obj = obj || window; var args = []; for(var i = 2; i < arguments.length; i++){ args.push(arguments[i]); } return function(){ //该语句相当于obj[strFn](args[0],args[1],...); obj[strFn].apply(obj,args); } } //定义类 Class1 function Class1(){ //构造函数 } Class1.prototype = { show : function(){ //如果有事件绑定则循环onshow数组,触发该事件 if(this.onshow){ for(var i = 0, len = this.onshow.length; i < len; i++){ this.onshow[i]();//调用事件处理程序 } } }, addEventOnShow : function (_eHandler){ this.onshow = this.onshow || [];//用数组存储绑定的事件处理程序引用 this.onshow.push(_eHandler); } } //创建class1实例 var obj = new Class1(); //创建obj的onShow事件处理程序 function objOnShow(userName){ alert('hello, ' + userName); } //事件一 var userName1 = 'xiaowang'; var onShow1 = createFunction(null,'objOnShow',userName1); //事件一 var userName2 = 'xiaoli'; var onShow2 = createFunction(null,'objOnShow',userName2); //绑定事件 obj.addEventOnShow(onShow1); obj.addEventOnShow(onShow2); //调用obj的show方法 obj.show();
以上实现把带参数和多绑定结合在一起,还可以增加一个removeEventOnShow来删除已注册的事件。
六、把对象注册为事件句柄
在编写面向对象的JavaScript程序时,如果想用对象作为事件句柄,那么可以使用如下的函数来注册它们:
function registerObjectEventHandler(element,eventtype,listener,captures){
element.addEventListener(eventtype,
function(event) {listener.handleEvent(event);},captures);
}
用这个函数可以把任何对象注册为事件句柄,只要它定义了handleEvent()方法。Firefox(以及其他基于Mozilla代码的浏览器)允许直接把定义了handleEvent()方法的事件监听器对象传递给addEventListener()方法而不是函数引用。对于这些浏览器来说,不需要我们刚才给出的特殊注册函数。
请看下面的例子
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>把对象注册为事件句柄</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> </head> <body> <input type="button" value = "点击我" id = "btn"> </body> </html> <script type="text/javascript"> <!-- var EventHandler = function(){} EventHandler.prototype.handleEvent = function(event){ alert('用对象作为事件句柄,只要实现该对象的方法handleEvent即可'); alert(event.type); } var objectHandler = new EventHandler(); var btn1Obj = document.getElementById("btn"); if(window.addEventListener){ btn1Obj.addEventListener("click",objectHandler,false); }else if (window.attachEvent){ //btn1Obj.attachEvent("onclick",objectHandler);//调用失败,说明不支持把对象注册为事件句柄 //btn1Obj.attachEvent("onclick",objectHandler.handleEvent); registerObjectEventHandler(btn1Obj,"onclick",objectHandler); } /** * 对于不支持把对象注册为事件句柄的浏览器,可以调用以下方法来实现 */ function registerObjectEventHandler(element,eventtype,listener,captures){ if(window.addEventListener){ element.addEventListener(eventtype, function(event) {listener.handleEvent(event);},captures); }else if (window.attachEvent){ element.attachEvent(eventtype, function(event) {listener.handleEvent(event);}); } } //--> </script>
发表评论
-
angular分析
2014-07-08 13:49 1067angular分析 -
键盘KeyCode值列表
2012-08-28 18:13 1106keycode 0 = keycode 1 = k ... -
JavaScript中的delete操作符
2012-04-20 14:17 1500主要从以下几个方面说 ... -
javascript性能优化之一
2012-04-04 21:01 0该篇文章转自 http://blog.sina.com.cn ... -
DOM节点中属性nodeName、nodeType和nodeValue的区别
2012-03-20 17:31 3744(一)nodeName 属性含有某个节点的名称。 元素节 ... -
javascript正则表达式总结
2012-03-16 13:53 1499正则表达式中特殊字符的含义 1、^ ^匹配输入字符串 ... -
javascript常用知识点总结(不断完善)
2011-07-04 17:15 1174一、函数中调用函数的实现 /** * 以下为 ... -
js对象的克隆
2011-06-14 15:02 2098由于js是采用引用传值的,故修改任何一个对象,其关 ... -
javascript中静态方法、实例方法、内部方法和原型的一点见解
2011-06-11 15:54 85951、静态方法的定义 var BaseClass = f ... -
javascript contains和compareDocumentPosition 方法来确定是否HTML节点
2011-03-30 17:41 14941、DOMElement.contains(DOMNode) ... -
事件mouseenter和事件mouseleave
2011-03-14 14:52 1821为了鼠标操作起来方便,IE实现了mouseenter 和m ... -
table列表中结合ctrl,shift实现多行的选择
2009-06-12 15:16 4424以下是简单的实现了tabl ... -
JavaScript中Array(数组)的属性和方法
2009-06-03 17:13 1406数组有四种定义的方式 ... -
表格自动换行
2008-12-02 11:06 3050有时表格中显示的内容不会根据长度的加长而自动换行,显示的效果很 ... -
让表格有滚动条的实现
2008-12-02 10:23 5631主要是用div样式来控制 例如 <html> ... -
利用javascript验证输入框中的值是否为日期格式
2008-09-02 15:45 127911、判断是否为年月日时间格式 <script> ... -
web一些值得珍藏的脚本代码
2008-08-01 09:50 13201. oncontextmenu="window.e ... -
div垂直和水平居中
2008-06-29 16:34 1743<div id="div_1" st ... -
JS创建日历控件
2008-06-29 16:32 1866// JavaScript Document /******* ... -
JS获取系统当前日期和时间
2008-06-29 16:31 6752<!DOCTYPE HTML PUBLIC " ...
相关推荐
为了解决这个问题,开发者设计并实现了自定义文件浏览器。这个自定义组件不仅包含了标准文件选择对话框的功能,还增加了对锁定文件的访问能力。它可能采用了以下技术: 1. **权限管理**:通过提升应用程序的权限...
本文将深入探讨如何为jQuery添加自定义事件机制,这将帮助开发者扩展jQuery的功能,实现更加个性化的交互逻辑。 首先,我们要了解jQuery的事件系统是基于浏览器的事件模型构建的。默认情况下,jQuery提供了如click...
`Qt`提供了丰富的图形界面元素和事件处理机制,使得开发者能够根据需求定制自己的界面组件。`QLabel`的自定义点击事件只是其中的一个例子,通过继承和事件处理,我们可以让界面更加互动和用户友好。在实际开发中,还...
在JavaScript的世界里,浏览器作为执行环境,提供了丰富的DOM事件和自定义事件机制,使得开发者能够更好地响应用户交互和应用状态变化。 一、DOM事件 DOM(Document Object Model)事件是浏览器原生支持的事件,如...
5. 浏览器控制:绑定事件监听,如地址栏的文本改变事件,当用户输入URL后,调用CEFSharp的Navigate方法加载网页。 6. 实现网页保存:添加保存按钮,点击时获取当前网页的HTML内容,保存为文件,并将所有资源文件...
这个自定义浏览器源码项目对于深入理解浏览器的工作机制,以及VC++与HTML的结合应用有着重要的实践意义。通过分析和修改源码,开发者可以进一步学习网络编程、UI设计和多线程处理等复杂主题,提高自己的编程技能。
- 避免过度依赖这些事件,因为它们可能会对性能造成影响,且浏览器的实现可能有所变化。 - 为了兼容性和最佳用户体验,应同时处理这两个事件,并理解它们之间的区别。 在实际开发中,我们还需要注意,由于跨域安全...
【Web浏览器和服务器的设计与实现】的开题报告主要探讨了在J2EE平台上使用Java语言开发Web浏览器和服务器的技术细节。在这个项目中,我们关注的是如何构建一个交互式的、功能丰富的Web浏览器,并且理解服务器如何...
标题“C# 简单浏览器源代码(无自定义控件)”指出这是一个基于C#编程语言实现的简单浏览器项目,它没有使用任何自定义的控件,这意味着开发者主要依赖.NET Framework提供的标准控件来构建用户界面。 【描述解读】 ...
这需要实现DragDrop机制,以及在TabControl中处理排序逻辑。 7. **多选模式**:虽然Safari默认只允许单个选项卡处于活动状态,但为了增加功能多样性,我们可以允许用户同时打开多个选项卡。 8. **关闭按钮**:在每...
自定义事件允许开发者定义事件的类型、携带的数据以及触发的时机,从而实现更灵活的事件处理机制。本文将详细介绍如何在JavaScript中创建和使用自定义事件。 自定义事件是JavaScript中一个强大的功能,它允许开发者...
本项目“Android自定义文件浏览器简单demo”提供了一个基础框架,可以帮助开发者快速实现这一功能。下面将详细讲解这个项目的知识点。 1. **自定义视图组件**: 在Android中,文件浏览器通常需要自定义ListView或...
总结起来,这个项目展示了如何利用Qt的组件和事件机制来构建一个具有高级特性的用户界面。通过结合QTabWidget和QToolBar,我们能够实现类似现代浏览器的多标签页功能,并且在需要时通过下拉菜单优雅地处理标签页的...
这个名为"一个简单的EventEmitter可在浏览器中使用帮助你实现事件的订阅和发布"的项目,就是为了解决这个问题,让开发者能够在浏览器端轻松地利用事件机制。 首先,让我们理解什么是`EventEmitter`。`EventEmitter`...
通过构建这样一个自定义js库,我们可以将这些常见的浏览器兼容性问题封装起来,让开发者能够更加专注于业务逻辑,而不需要担心底层实现的差异。同时,这个库也应该保持更新,以便随着新的浏览器特性的推出,持续提供...
总结来说,"GalleryDemo"项目展示了如何在Android平台上构建一个功能完备的图片浏览器,包括使用自定义视图或现有组件来实现滑动和缩放,以及应用各种图片加载和手势处理技术。对于Android开发者来说,理解和实现...
7. 缓存机制:为了提高用户体验,浏览器通常需要实现缓存机制。Android的`WebView`支持HTTP缓存,通过`WebSettings`的`setCacheMode()`方法可以控制缓存模式。还可以自定义缓存策略,例如使用`SQLite`数据库或`...
这篇文章的重点是介绍如何使用JavaScript中的window对象的onresize事件来实现当浏览器窗口大小改变时触发事件的功能。以下是关于这一知识点的详细解析。 首先,我们了解window对象。在浏览器中,window对象表示一个...
这意味着这个自定义浏览器可能是一个基于C#或Visual Basic .NET的Windows桌面应用,利用了Winform库来实现用户界面和交互。 在压缩包文件列表中,“浏览器”可能是该自定义浏览器的可执行文件或其他相关组件。通常...
### 阻止浏览器的默认事件和冒泡 ...通过以上介绍,我们可以了解到在实际开发中如何有效地使用JavaScript来控制和管理浏览器的默认事件以及事件的冒泡机制,从而实现更复杂的功能和更好的用户体验。