搜索
首页web前端js教程Javascript 事件流和事件绑定_javascript技巧

事件流

浏览器中的事件流意味着页面上可有不仅一个,甚至多个元素响应同一个事件。而这一个或多个元素响应事件发生的先后顺序在各个浏览器(主要针对IE和Netscape)上是不同的。

冒泡型事件(Dubbed Bubbling)

IE上的解决方案就是冒泡型事件(Dubbed Bubbling)。冒泡型事件的基本思想是,事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。

示例(1):点击我触发冒泡型事件流

示例(1)的XHTML代码结构:
<br><span id="cnt0"><br>     <a href="%E2%80%9D#1%E2%80%B3" id="”link0″">点击我触发冒泡型事件流</a><br></span><br>

这个示例里我同时给span和a标签绑定了click事件,大家看到了,我们点击这个a标签,一次点击(click)同时触发了两个元素a和span的事件。先触发的是绑定给a标签的click事件,然后触发的是span标签的click事件。也就是前面提到的“页面上可有不仅一个,甚至多个元素响应同一个事件”和“事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发”。

这个示例里我们点击的第一目标是a标签这个链接,它就是前面提到的“最特定的事件目标”,然后才是span这个相对“不特定的事件目标”。再看看我的XHTML代码结构,你会发现a标签包含在span标签中,也就是说span是a标签的父节点,如果大家还不是很清晰的知道他们之间的关系,让我们看看下面的这个DOM树的结构图:

示例(1)

事件触发的顺序是从最特定的目标,沿着DOM树不断的向上触发click事件,就像气泡从下一直上冒的过程一样。“冒泡型”也就是这么得来的,也很形象。这里要说明的是,由于我只给a和span绑定了click事件,所以“冒”到span就到顶了,如果你也给包含他们的p标签还有document绑定click事件,这个冒泡的过程就会一直延续到document的事件触发才结束。

另外要说明的是,在IE5.5中冒泡的最高层DOM节点为document,IE6中则可以支持html节点。在Mozllia1.0及之后的版本也支持冒泡,而它则更可以冒到window窗口对象。

捕获型事件(Event Capturing)

相对IE4.0,Netscape4.0则使用的是捕获型事件的解决方案。这个事件触发的过程则正好和冒泡相反——在捕获型事件中,事件从最不精确的对象(document对象)开始触发,然后到最精确的对象。还是前面的示例,不过现在换由捕获型事件触发(当然你需要在Netscape或Firefox中测试)。

示例(2):点击我触发捕获型事件流

示例(2)的XHTML代码结构:
<br><span id="cnt1"><br>     <a href="%E2%80%9D#1%E2%80%B3" id="”link1″">点击我触发捕获型事件流</a><br></span><br>

事件触发的循序正好跟前面的冒泡相反,这里我就不赘述了。

DOM 事件流

这个事件流则是W3C制定一个标准规范,它同时支持两种事件流模式,不过是先发生捕获型事件流,再发生冒泡型事件流。

DOM事件流最独特的是,它支持文本节点也触发事件(IE中这不支持)。不过说实话,我现在还看不出来让文本节点支持事件有什么作用。

最后要说的是,根据最近大家在开发的实践过程中的运用,我们一般都采取冒泡型的事件流触发方式,这点我们的IE做的比较成功。至于原因,我想你可以通过上面的解释可以看出,毕竟我们给元素触发事件,肯定是希望从我们最希望先触发(从最精确的)的那个开始。而DOM的先捕获后冒泡我觉得只能用让我很疑惑来形容我的感受。因为如果按照DOM的事件流,我们的事件要被触发2次,而我们一般都只会选择一个类型的事件流,值希望触发一次,很难理解当初W3C是怎么想的?!一个字——晕!可能我的理解能力有限,不过这是我的真是感受。

事件处理函数/监听函数

这里我不想做过多的介绍,我们知道在IE里使用attachEvent(”NAME_OF_EVENT_HANDLER”, fnHandler)给元素绑定事件,而在支持DOM事件流的浏览器里,则使用addEventListener(”NAME_OF_EVENT_HANDLER”, fnHandler, isCapture)。前面我控制FIREFOX中触发捕获事件流,就是通过设置isCapture(ture:捕获;false:冒泡)做到的。还有就是我们传统element.onclick或者element['on'+eventName],这个是所有浏览器都支持的事件绑定的监听器,而且我测试的结果XP下的IE6~8、Firefox2.0~3.5、Safari4.0、Opera9.6.4、Chrome2.0.180都是以冒泡的事件流触发的。更老的浏览器我就没有测试过了,不过根据《Pro Javascript Techniques》里介绍,老的浏览器使用onclick这样的事件绑定,触发的也是冒泡事件流。如果你有兴趣可以淘下那些古董浏览器,测试一番。不过还是有不支持冒泡的事件的,下面我们就讲讲。

那些事件是支持冒泡,那些不支持?

这个是比较有意思的,这里的总结都来自PPK在YAHOO的演讲《Javascript Event》(推荐大家一定看看,很经典!),简单总结PPK的内容,基本上只有onload、unload、focus、blur、submit和change事件是不支持冒泡的,这也是我在前面说“一般使用冒泡事件流”。自然向keydown、keypress、keyup、click、dbclick、mousedown、mouseout、mouseover、mouseup、mousemove。用PPK的话说,那就是“Mouse and Key Events”支持冒泡,而Interface Events(也就是《Javascript高级程序设计》里的HTML(HTML是来构建interface的)事件。)则只支持捕获。

他又说了下是,click是“最安全的”事件,它即支持冒泡,又支持捕获。鼠标事件可以触发click,键盘事件也可以触发click。还有就是在支持DOM事件的浏览器里,focus和blur是只支持捕获的,所以如果你如果用到我下面给出的addEvent函数,在给元素绑定focus或则blur事件时,bCapture一定要设置为true。那么这里就发生了一个问题,IE是不支持捕获的,那不是触发不了这连个事件?呵呵,是个严重的问题哦?不过在IE里使用focus和blur事件的时候,其实触发的是IE的focusin和focusout,当然这两个事件也是只支持冒泡的。

PPK虽然这么说,但是我还是想实践一下,于是我这里这么处理了下,window.onfocus = function(){alert('ok')},lnkOne.onfocus = demoClick;有趣的事情发生了!在IE6里,当你点击我的第一个示例链接,呵呵,视乎是即冒泡完了又捕获了,在IE8中则只冒泡了,不过这个只是你点这个链接的时候发生的情况。接着我又算是试探性地“无意中”测试了下,点击其他的应用程序,又一个让我意想不到的情况发生了,居然先触发了window.onfocus,接着触发了lnk.onfocus!!于是我立刻测试了IE6,一样!视乎IE也“疯狂”了一把,触发了onfocus的捕获哦,哈哈!!!难道IE也支持捕获,IE也疯狂???!!!!还是这个现象有其他的解释??疑惑!?!?!!呵呵,起初我确实这么想,让我惊喜了一把,不过仔细想了想,只是事件执行顺序的原因造成了这样的假象。

呵呵,原来在IE6里,点击链接,先触发了onfocus,弹出提示‘A',然后关闭弹出的提示框窗口时,窗口又获得了焦点,又触发了window的焦点事件。然后是触发了A标签的的click事件,然后关闭弹出的提示窗口时,又让窗口获得了焦点,然后又是A标签获得焦点。而IE8测试正确的,当触发了click事件后,再关闭提示窗口的时候,就不在触发window的focus。哎!空欢喜了一场,我还以为windows的IE支捕获呢!!不过也不是完全没有收获,如果你也像我这么整了,你要注意IE6会折腾两次的,不过只是在你点击的时候才会这样,如果用tab切换获得焦点,就只会触发A标签的focus事件了。

还有在Firefox(我测试的最新的3.5)中,可千万别window.onfocus,不然你就挂了!很抱歉用FIREFOX看我这篇帖子的人,OK了几次后,你就挂了!!呵呵!!!

What is ‘this'?

IE在前面给了我“惊喜”,this也给我惊喜。当然主要是我以前没有注意到,但是YAHOO的工程师们早以发现了。this这个关键字是根据上下文来决定的,在我们的事件绑定的功能函数里,this应该是指向当前的元素节点对象,应该是一个Element对象。我想这个大家应该好理解:

示例代码:

<br><span id="cnt0"><br>     <a href="%E2%80%9D#1%E2%80%B3" id="”link0″">点击我触发捕获型事件流</a><br></span>


这段代码正式我在示例(1)中的处理方式,示例中this指向的a标签这个element对象,所以我们可以得到a标签的tagName这个属性‘A'。示例(2)里,我使用一个兼容的事件监听函数:

<br>function addListener(el, event, fn, bCapture){<br>  var isCapture = bCapture ? bCapture : false;<br>  try {<br>    el.addEventListener(event, fn, isCapture);<br>  } <br>  catch (e) {<br>    try {<br>      el.attachEvent('on' + event, fn);<br>    } <br>    catch (e) {<br>      el['on' + event] = fn;<br>    }<br>  }<br>}<br>

在我们的支持DOM事件流的浏览器里,我们也可以得到正确的提示this.tagName为‘A'。this出现问题就在IE中,当我们使用attachEvent给元素绑定事件,现在你点击下面的链接:

示例(3):What is ‘this'?

示例代码:

    What is ‘this'?

function whatIsThis(){
    if (this === window) {
        alert('This is a window object');
    }
    alert('So, This.tagName is:'+ ‘‘'+ this.tagName +''。');
}

addListener(lnkThree, ‘click', whatIsThis);
addListener(cntThree, ‘click', whatIsThis);

看清楚了吗?如果你在IE6~8中测试,那么你点的是window对象而不是一个a标签。晕倒!!!-_-! 所以你要小心,问题多多啊,要解决这个this关键字的问题,我给你的建议就是你可以考虑直接用传统的'onclick'或者修改下前面的绑定事件监听的函数:

修改后的代码:
<br>function addEvent(el, event, fn, obj, overrideContext, bCapture){<br>  var context = el, isCapture = bCapture ? bCapture : false, wrappedFn = null;

  if (overrideContext) {
    if (overrideContext === true) {
      context = obj;
    }
    else {
      context = overrideContext;
    }
  }
  wrappedFn = function(){
    return fn.call(context);
  };
  try {
    el.addEventListener(event, wrappedFn, isCapture);
  }
  catch (e) {
    try {
      el.attachEvent('on' + event, wrappedFn);
    }
    catch (e) {
      el['on' + event] = wrappedFn;
    }
  }
}

示例(4):再点点我,看我的‘this'是什么?

好了就这么多了,不知道对你有没有帮助,最后说明下,本文中的部分观点参考至《Javascript高级程序设计》(很好的一本书,推荐大家看看!),addEvent函数借鉴了YUI2.7的_addListener方法,这里也要谢谢YUI那些牛人,向他们致敬!

静态页访问地址:http://img.jb51.net/online/jsevent/event.htm(如果你也想体验下我的“惊喜”,请用IE6访问,点击第一个示例链接,但千万不要用Firefox,否则会挂掉,别说我没有提醒你!!!)

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
es6数组怎么去掉重复并且重新排序es6数组怎么去掉重复并且重新排序May 05, 2022 pm 07:08 PM

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

JavaScript的Symbol类型、隐藏属性及全局注册表详解JavaScript的Symbol类型、隐藏属性及全局注册表详解Jun 02, 2022 am 11:50 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

原来利用纯CSS也能实现文字轮播与图片轮播!原来利用纯CSS也能实现文字轮播与图片轮播!Jun 10, 2022 pm 01:00 PM

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

JavaScript对象的构造函数和new操作符(实例详解)JavaScript对象的构造函数和new操作符(实例详解)May 10, 2022 pm 06:16 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

javascript怎么移除元素点击事件javascript怎么移除元素点击事件Apr 11, 2022 pm 04:51 PM

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

JavaScript面向对象详细解析之属性描述符JavaScript面向对象详细解析之属性描述符May 27, 2022 pm 05:29 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

foreach是es6里的吗foreach是es6里的吗May 05, 2022 pm 05:59 PM

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。

整理总结JavaScript常见的BOM操作整理总结JavaScript常见的BOM操作Jun 01, 2022 am 11:43 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具