- 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, {});
- 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修饰,在页面上面是如下效果:
那么点击儿子的时候,会点击到爸爸和爷爷吗?
如图所示,会触发爸爸和爷爷的监听事件。
这种从里面的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就可以了。
以下是一个模型图:
其实是以(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);
这个时候不能按那个访问顺序考虑,其实是哪个先写就哪个先执行。上述代码就先输出“儿子冒泡”,然后输出“儿子捕获”。