正在加载...

事件监听器

衣帽间里有一个挂钩。按钮是 #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 这个词开始,只在监听函数里面改变。

还没有人在听

文件从按钮和段落开始。还没有加上监听。点击会执行,下面两次输出问的是票根和按钮上的字。

安静的挂钩

javascript
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。

加上,先不运行

javascript
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。

一个监听

javascript
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。

两个都运行

javascript
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。

移除 wool

javascript
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。它不写按钮文字。也不读事件参数。

页面演示 — 挂钩

html
<!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。下一页是事件对象。它读取这些函数没有接收的参数。

挂钩上的五次检查

  1. 没有监听时点击。票根是 blank,按钮是 hang。
  2. 加上 wool,不要点击。票根是 blank,parts.length 是 0,按钮是 hang。
  3. 加上 wool,然后点击。票根是 wool,按钮是 hang,parts.length 是 1。
  4. 先加 wool,再加 silk,点击一次。票根是 wool silk,parts.length 是 2,按钮是 hang。
  5. 两个都加上,移除 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

🧠 测试您的知识

准备开始

测试您的知识

通过这个互动测验挑战自己,看看你对这个主题的理解程度如何

❓
8
问题
🎯
70%
及格要求
♾️
∞
时间
🔄
∞
尝试次数

📝 说明

  • 仔细阅读每个问题
  • 为每个问题选择最佳答案
  • 您可以随时重新参加测验
  • 您的进度将显示在顶部