事件监听器
衣帽间里有一个挂钩。按钮是 #peg,上面写着 hang。下面的 #ticket 还是 blank。
上一页是门铃和 onclick 属性。那里只有一个位置。第二个函数会换掉第一个。这一页不写那个属性。typeof 和 this 也属于那一页。
这一页是 addEventListener。调用把函数加进按钮的点击列表。这一行本身不运行它。在 peg.click() 之前,票根一直是 blank。
先加 wool,再加 silk。第二个不会把第一个挤掉。一次点击两个都运行:先 wool,后 silk。票根变成 wool silk。按钮上的字还是 hang。
同一个 wool 函数加两次,第二次什么也不加。一次点击,运行一次。
removeEventListener 去掉的是你加进去的那个函数。新函数即使行文一样,也是另一个对象。wool 还在。
页面脚本把两个都加上,再点击一次。挂钩下面这一行是 wool silk / 2 / peg。这里不创建元素,不写样式,也不读事件参数。那是下一页。
两个钩子,不是一个位置
getElementById 只把按钮和票根段落交给你。每次 addEventListener 都可以再放一个监听在旁边。点击会按列表从头跑到尾。这些函数不接收参数。事件对象是下一页。
谁在听
按钮从 hang 开始,下面是 blank。按顺序读每一行。除了页面那一行,每个片段都从新按钮开始。页面那一行是底下的演示。那个演示不移除任何人。
📊 谁在听
| 时刻 | 谁在听 | 票根文字 | 容易混 |
|---|---|---|---|
click,还没有监听 |
没有人 | blank | 以为空点击会写出 wool |
给 wool 调用 addEventListener,在 click 之前 |
wool | blank | 以为添加本身会写出 wool |
只有 wool 时 click |
wool | wool | 以为按钮文字变成 wool |
先 wool 再 silk,一次 click |
两个,先 wool 后 silk | wool silk | 以为只跑第二个 |
对 wool 调用 removeEventListener,再 click |
silk | silk | 以为两个还在跑 |
页面脚本,一次 click |
两个 | wool silk | 以为这一行以 hang 结尾 |
addEventListener("click", wool) 把 wool 放到点击列表末尾。它不调用 wool。peg.click() 发出一次点击,并从列表开头往下跑。按钮自己的文字不变。
之后加上的 silk 坐在 wool 后面。两个都会运行。顺序就是添加的顺序。
同一个函数对象不会加两次。peg.addEventListener("click", wool) 再写一次同样的调用,列表里仍然只有一个。一次点击让 wool 运行一次。parts.length 是 1,票根是 wool。
removeEventListener("click", wool) 去掉那个对象。如果你加过 silk,silk 还在。一个也会 push "wool" 的新函数对不上。在 peg.removeEventListener("click", function () { parts.push("wool"); }) 之后,原来的 wool 仍在列表里。点击还是会写出 wool。
join(" ") 只在 parts 里已有的词之间放一个空格。这里不拼接空列表。票根从 blank 这个词开始,只在监听函数里面改变。
还没有人在听
文件从按钮和段落开始。还没有加上监听。点击会执行,下面两次输出问的是票根和按钮上的字。
let peg = document.getElementById("peg");
let ticket = document.getElementById("ticket");
peg.click();
console.log(ticket.textContent);
console.log(peg.textContent);
输出是 blank 和 hang。点击列表是空的。段落没有变。
监听在等
addEventListener 把 wool 存起来。函数体不在这一行运行。parts 仍是空的,票根仍是 blank,按钮仍写着 hang。
let peg = document.getElementById("peg");
let ticket = document.getElementById("ticket");
let parts = [];
function wool() {
parts.push("wool");
ticket.textContent = parts.join(" ");
}
peg.addEventListener("click", wool);
console.log(ticket.textContent);
console.log(parts.length);
console.log(peg.textContent);
输出是 blank、0 和 hang。wool 在列表里。还没有人调用它,所以 parts 里没有词。
click 运行列表里的函数
这一段再次从新按钮开始。只加上 wool,然后 peg.click()。票根变成 wool。按钮文字仍是 hang。parts.length 是 1。
let peg = document.getElementById("peg");
let ticket = document.getElementById("ticket");
let parts = [];
function wool() {
parts.push("wool");
ticket.textContent = parts.join(" ");
}
peg.addEventListener("click", wool);
peg.click();
console.log(ticket.textContent);
console.log(peg.textContent);
console.log(parts.length);
输出是 wool、hang 和 1。一个监听,一个词。hang 仍是按钮上的字。
silk 坐在 wool 旁边
新按钮。先加 wool,再加 silk,然后才一次 click。两次添加之间没有点击。wool 放入 "wool" 并写出来。silk 放入 "silk",再用空格写出两个词。票根是 wool silk。parts.length 是 2。按钮仍是 hang。
let peg = document.getElementById("peg");
let ticket = document.getElementById("ticket");
let parts = [];
function wool() {
parts.push("wool");
ticket.textContent = parts.join(" ");
}
function silk() {
parts.push("silk");
ticket.textContent = parts.join(" ");
}
peg.addEventListener("click", wool);
peg.addEventListener("click", silk);
peg.click();
console.log(ticket.textContent);
console.log(parts.length);
console.log(peg.textContent);
输出是 wool silk、2 和 hang。silk 没有擦掉 wool。一次点击按添加顺序跑完列表。
把 wool 从挂钩上取下
新按钮。两个函数都加上,然后用同一个 wool 函数调用 removeEventListener。silk 留下。一次 click 只运行 silk。票根是 silk,不是 wool silk。parts.length 是 1。
let peg = document.getElementById("peg");
let ticket = document.getElementById("ticket");
let parts = [];
function wool() {
parts.push("wool");
ticket.textContent = parts.join(" ");
}
function silk() {
parts.push("silk");
ticket.textContent = parts.join(" ");
}
peg.addEventListener("click", wool);
peg.addEventListener("click", silk);
peg.removeEventListener("click", wool);
peg.click();
console.log(ticket.textContent);
console.log(parts.length);
console.log(peg.textContent);
输出是 silk、1 和 hang。wool 就是你加进去的那个对象,所以离开了列表。下面的演示不移除任何人。
挂钩下面的一行
脚本在 body 末尾,按钮和段落已经存在。它先加 wool,再加 silk,然后调用一次 click。每个函数把 hits 加 1,并放入自己的词。这一行接上票根文字、次数和 peg.id。它不写按钮文字。也不读事件参数。
<!DOCTYPE html>
<html>
<head>
<title>event-listeners — page</title>
</head>
<body>
<button id="peg" type="button">hang</button>
<p id="ticket">blank</p>
<p id="line">…</p>
<script>
let peg = document.getElementById("peg");
let ticket = document.getElementById("ticket");
let parts = [];
let hits = 0;
function wool() {
hits = hits + 1;
parts.push("wool");
ticket.textContent = parts.join(" ");
}
function silk() {
hits = hits + 1;
parts.push("silk");
ticket.textContent = parts.join(" ");
}
peg.addEventListener("click", wool);
peg.addEventListener("click", silk);
peg.click();
document.getElementById("line").textContent =
ticket.textContent + " / " + hits + " / " + peg.id;
</script>
</body>
</html>
这一行是 wool silk / 2 / peg。票根是 wool silk,不是 blank。次数是 2,因为两个监听在一次点击里都运行了。最后一个词是按钮的 id,peg.id,不是 hang。按钮上仍是 hang。下一页是事件对象。它读取这些函数没有接收的参数。
挂钩上的五次检查
- 没有监听时点击。票根是 blank,按钮是 hang。
- 加上 wool,不要点击。票根是 blank,
parts.length是 0,按钮是 hang。 - 加上 wool,然后点击。票根是 wool,按钮是 hang,
parts.length是 1。 - 先加 wool,再加 silk,点击一次。票根是 wool silk,
parts.length是 2,按钮是 hang。 - 两个都加上,移除 wool,再点击。票根是 silk,
parts.length是 1,按钮是 hang。读页面这一行:wool silk / 2 / peg。
这个挂钩会在哪里骗人
按钮上仍是 hang。列表里曾经有两个函数,或者只有 silk,或者没有人。
- 以为第二个
addEventListener会换掉第一个,像onclick那样 - 以为
addEventListener自己就会把票根写成 wool - 以为两个都加上时只有 silk 会运行
- 以为按钮文字会变成 wool
- 以为用一个新函数调用
removeEventListener就能去掉 wool - 把同一个
wool函数加两次,还指望它运行两次 - 在这里读
onclick、typeof null或this.id;那是门铃那一页 - 在这里读
event.target;这些函数不接收参数,事件对象是下一页 - 用
createElement造按钮;那是更早的一页 - 把这一行读成 blank / 0 / hang
留下的几点
- 没有监听时,
peg.click()让票根保持 blank,按钮保持 hang addEventListener在click之前让票根保持 blank- 只有 wool 时点一次,票根变成 wool,按钮仍是 hang
- 先 wool 再 silk,再点一次,票根变成 wool silk
- 用同一个 wool 调用
removeEventListener再点击,票根变成 silk - 同一个 wool 加两次只运行一次,新函数去不掉它
- 页面这一行是 wool silk / 2 / peg
🧠 测试您的知识
测试您的知识
通过这个互动测验挑战自己,看看你对这个主题的理解程度如何
📝 说明
- 仔细阅读每个问题
- 为每个问题选择最佳答案
- 您可以随时重新参加测验
- 您的进度将显示在顶部