dom的事件传递过程-webkit

来源:互联网 发布:堆排序java 编辑:程序博客网 时间:2024/06/06 19:07

今天又有人问我,在页面上的一些点击事件是怎么传递的,看webkit的源码里面整个eventhandler和Node的处理函数感觉很混乱和复杂,其实关于dom的事件处理规范说的很清楚,这里简单描述一下。


1、某一次对页面的触碰,webkit会通过EventHandler对象的hittest计算出来坐标对应的一个节点,被称为targetNode

2、由于页面的复杂性,可能在1中的targetNode的父辈节点也对本次事件感兴趣,因为为了给父辈节点一次处理事件的能力,规范里面提出了事件传递的两种模式:捕获(capture)与冒泡(bubble),前者是在DOM树上自顶向下传播事件,后者则是从targetNode开始自底向上传播事件,无论哪种方式的传递,事件都只是在父子关系链上传递,对应的兄弟节点是没有权力来处理事件了。

3、如2描述,则事件可能会传递两次给相同的节点,那么节点是在何时处理对应事件的呢?webkit默认的处理都是在冒泡里面,但是js在绑定事件的时候可以指定是否在捕获的过程中处理事件,如下事件绑定的idl定义:

        [OldStyleObjC] void addEventListener(in DOMString type,
                                             in EventListener listener,
                                             in [Optional] boolean useCapture);

对应js的调用就类似:addEventListener("click", onBody, true)//click是事件名称,onBody是js回调函数,true则表示onBody在事件的捕获过程中处理,默认为false,即在冒泡中处理。


原理就如上,来看一个实际的例子吧

<html>
<body id="body">
 <div id="div">
  <img src="http://www.baidu.com/img/bd_logo.png"  id="img"></img>
 </div>

 <script type="text/javascript">
 function onBody(event) {
     console.log("on body");
 }

 function onDiv(event) {
     console.log("on div");
 }

 function onImg(event) {
     console.log("on img");
     //event.bubbles=true;
 }

 window.onload = function() {
     document.getElementById("img").addEventListener("click", onImg);
     document.getElementById("div").addEventListener("click", onDiv);
     document.getElementById("body").addEventListener("click", onBody);
 }

 </script>
</body>
</html>

页面源码很简单,在window的onload事件(PS:window.onload等同于body.onload,之前核实过webkit的代码,两者的触发时机是一致的,因为head标签不会干扰onload事件)触发时候执行匿名函数,分别为img/div/body绑定click事件的监听。


点击图片以后,通过chrome devtools里面的console来查看事件的处理顺序,结果如下


事件处理结果是否设置捕获\元素divbody结果 truetrue

on bodyevent.html:9
on divevent.html:13
on img
 truefalse
on divevent.html:13
on imgevent.html:17
on body
 falsetrue
on bodyevent.html:9
on imgevent.html:17
on div
 falsefalse
on imgevent.html:17
on divevent.html:13
on body
如第一行,div与body都设置为capture处理click事件,因此我们点击img的时候,事件从body->div->img的父子关系线开始捕获方式传递事件(冒泡顺序img->div->body),因此事件触发则为body/div/img

其他行的结果依次类推,不再描述。


另外,规范也提供了手段来随时中断上述的事件传递过程,js调用event.stopPropagation()来阻止事件的进一步传递,例如

 function onBody(event) {
     console.log("on body");
     event.stopPropagation();
 }

那么,我们会看到body处理函数调用以后,整个事件传递就结束了;若body是在捕获过程中阻止了事件的继续传递,甚至连img都无法处理click事件了。

如此的设计下,整个dom的事件处理就能够非常灵活,页面可以自己选择在不同场景下让不同元素来响应click事件了


so,到目前为止事件传递的原理已经说得差不多了,其实我们了解了这些就足够了,至于是否需要去搞清楚webkit里面对该原理的具体实现就看个人兴趣了。


over




0 0
原创粉丝点击