DOM事件模型

2018-10-08  本文已影响0人  Jason_Shu
  1. DOM level 0
    我们来看看如下代码:

html代码:

<body>
  <button id="X" onclick="print">A</button>
  <button id="Y" onclick="print()">B</button>
  <button id="Z" onclick="print.call()">C</button>
</body>

JS代码:

function print() {
  console.log("hi");
}

X.onclick = print;  // 类型为函数
Y.onclick = print();  //  undefined
Z.onclick = print.call();

大家觉得A,B,C,X,Y和Z哪几个能执行print函数呢?

答案是: B,C,X

在html中的button上的onclick属性里面是「要执行的代码」,onclick="要执行的代码",一旦用户点击,浏览器就eval(“要执行的代码”)。在这里也就是eval("print()").

但是JS中的X.onlick,onclick相当于X的属性,这个属性是一个函数(print)。一旦用户点击,那么浏览器就执行X.onclick.call(x, {});

  1. DOM level 2
    html代码:
<button id="xxx">click</button>

JS代码:

xxx.addEventListener("click", function() { console.log("hi"); });

xxx.onclick = function() { console.log("hi"); });

那这么写与DOM level 0 有啥区别呢?

xxx.onclick是对属性的操作,这个属性唯一,如果想要有两个以上的onclick事件,就不行了。

xxx.onclick = function() {
  console.log(2);
}

xxx.onclick = function() {
  console.log(3);
}

在上述代码中,下面的onclick就会覆盖上面的onclick。

而addEventListener这个模型是一个队列(xxx拥有一个队列 eventListeners)。

接下来我们再说说,事件的「捕捉」和「冒泡」。
html代码:

  <div id="grand">
        爷爷
        <div id="father">
            爸爸
            <div id="son">
                儿子
            </div>
        </div>
    </div>

JS代码:

grand.addEventListener("click", function() {
    console.log("爷爷");
}, false);

father.addEventListener("click", function() {
    console.log("爸爸");
}, false);

son.addEventListener("click", function() {
    console.log("儿子");
}, false);

通过一定的CSS修饰,在页面上面是如下效果:


image.png

那么点击儿子的时候,会点击到爸爸和爷爷吗?

image.png

如图所示,会触发爸爸和爷爷的监听事件。

这种从里面的div往外层div的监听事件就是「事件冒泡」。从外层向里层的监听事件就是「事件捕捉」。

如果执行「事件捕捉」?

grand.addEventListener("click", function() {
    console.log("爷爷");
}, true);

father.addEventListener("click", function() {
    console.log("爸爸");
}, true);

son.addEventListener("click", function() {
    console.log("儿子");
}, true);

只需要把addEventListener的第三个参数换成true就可以了。


image.png

以下是一个模型图:


image.png

其实是以(1)到(6)的顺序来访问的。(fn1,fn2,fn3分别代表爷爷,爸爸,儿子的输出函数)。
在我们把三个监听事件都设置为false的时候,fn1、fn2、fn3分别在图中(4)(5)(6)的位置,按照访问顺序,固然输出“儿子”,“爸爸”,“爷爷”。

那我们如果单独把爸爸那个监听函数的false改为true呢?

grand.addEventListener("click", function fn1() {
    console.log("爷爷");
}, false);

father.addEventListener("click", function fn2() {
    console.log("爸爸");
}, true);

son.addEventListener("click", function fn3() {
    console.log("儿子");
}, false);

此时,fn2函数会出现在(2)处,而fn1和fn3会出现在(4)和(6)处。按照访问顺序,则会输出“爸爸”,“儿子”, “爷爷”。

那如果只对同一个div监听,既冒泡也捕获呢?


son.addEventListener("click", function() {
    console.log("儿子冒泡");
}, false);

son.addEventListener("click", function() {
    console.log("儿子捕获");
}, true);

这个时候不能按那个访问顺序考虑,其实是哪个先写就哪个先执行。上述代码就先输出“儿子冒泡”,然后输出“儿子捕获”。

上一篇 下一篇

猜你喜欢

热点阅读