JS DOM Event
- 采用事件驱动模式,任务的执行不取决代码的顺序,而取决于某一个事件是否发生。
1. 事件冒泡Bubbling
1.1 Bubbling
When an event happens on an element, it first runs the handlers on it, then on its parent, then all the way up on other ancestors.
The process is called “bubbling”, because events “bubble” from the inner element up through parents like a bubble in the water.
就是如果事件发生在内部子元素上,这个事件也会触发父元素的该事件处理器。比如父元素有onclick = "myFunction()",你没按父元素但按了里面的子元素,父元素的myFunction()会被触发运行。这个被按的子元素是这个event的target,用event.target
可以找到
function changeBgColor() {
if (event.target.style.backgroundColor === "pink") {
event.target.style.backgroundColor = "yellow";
} else {
event.target.style.backgroundColor = "pink";
}
}
1.2 Stop Bubbling
If we don't want the parent element handler to be triggered by child element, you can stop bubbling. ONLY stop bubbling if you really need it, otherwise bubbling is convenient.
不想让子元素的事件冒泡上来,在该子元素上用method event.stopPropagation()
<div onclick = "myFunction()">
<p onclick = "event.stopPropagation()">
paragrah text.
</p>
</div>
2. 事件捕获Capture
如果说bubbling是从下往上,那么capture就是从上往下,从外层父元素一直到target所在的元素。通常用on<event>这种格式,或者用addEventListener设置的handler,不执行capture,只执行bubbling。如果要让他们执行capture,要设置{capture: true}。
<body>
<div>
<p id="p1">
<input type="button" id="captureDemo" />
</p>
</div>
<script>
var demo = document.getElementById("captureDemo");
var p1 = document.getElementById("p1");
demo.addEventListener("click", e => alert("Capturing demo"), true);
p1.addEventListener("click", e => alert("Capturing p1"), true);
</script>
</body>
上述例子中,由于p1和captureDemo都设置了capture:true,所以点button的时候,会先显示"Capturing p1", 再显示"Capturing demo",从外到内。
3. 事件委托Event Delegation
翻译成中文叫事件委托或者事件代理。因为event handler过多会影响页面性能,把一些子元素的event handler统一放到他们的共同爸爸那里,减少handler数量,能更快访问。
The idea is that if we have a lot of elements handled in a similar way, then instead of assigning a handler to each of them – we put a single handler on their common ancestor.
In the handler we get event.target
, see where the event actually happened and handle it.
4.事件监听后触发函数的参数传递
When an event happens, your assigned function will be invoked, and the "event" will be the default first parameter of the function. 用addEventListener时,event是默认形参,就跟array.reduce(function(prev, curr) {})里面默认传prev,curr一样。
element.addEventListener("click", myFunction);
function myFunction() {};
element.addEventListener("click", function () {}); //里面第二个参数可以是直接的函数表达式或者一个函数名字,函数内容在外部定义
element.onclick = "myFunction()"; //这里加引号,里面直接调用函数运行所以函数后面加括号
对于event则放在函数定义里面作为形参(符号无所谓),具体哪个event会作为实参传进来:
document.getElementById("myBtn").addEventListener("click", myFunction);
function myFunction(event) {
document.getElementById("demo").innerHTML = "Hello World";
alert(event.target); //这里event作为形参的话其实符号无所谓,比如可以写成function myFunction(e){alert(e.target);}, 反正到时候具体那个event会作为这个e被传进来
function myFunction() {
document.getElementById("demo").innerHTML = "Hello World";
alert(event.target); //这样也work,因为event直接绑定了,这里的event是固定符号。但最好还是写上event传递,便于代码阅读
对于onclick = "functionName()"中,event也是默认绑定,可以不用传。如果要传递,在onclick那句语句中以实参传递,函数定义的时候写上形参。
<button onclick="displayDate()">The time is?</button>
<script>
function displayDate() {
document.getElementById("demo").innerHTML = Date();
alert(event.target);
}
</script>
<button onclick="displayDate(event)">The time is?</button>
<script>
function displayDate(e) {
document.getElementById("demo").innerHTML = Date();
alert(e.target);
}
</script>