javascript - 为什么只有所有其他 HTML 元素对“点击”做出反应?
问题描述
非常基本 - 作为对元素“点击”的反应,它的类应该切换。只要只注册一个事件处理程序就可以工作。如果为其他元素注册多个,那么只有每个其他元素才会改变它的类。我感觉这与事件冒泡有关,但感觉还不够。我很想知道为什么会发生这种情况以及如何控制它。所以这就是我到目前为止得到的:
HTML
<body>
<main>
<div>
<p>
<a>I'm an a-element.</a>
</p>
</div>
</main>
</body>
CSS
main {
height: 500px;
width: 900px;
background-color: black;}
div {
height: 400px;
width: 700px;
background-color: dimgray;}
p {
height: 300px;
width: 500px;
background-color: darkgray;}
a {
height: 200px;
width: 300px;
background-color: lightgray;}
.gold {
background-color: gold;}
JS
function setGold(event) {
event.target.classList.toggle("gold");
}
function setup() {
document.getElementsByTagName("a")[0].addEventListener("click", setGold);
document.getElementsByTagName("p")[0].addEventListener("click", setGold);
document.getElementsByTagName("div")[0].addEventListener("click", setGold);
document.getElementsByTagName("main")[0].addEventListener("click", setGold);
}
window.addEventListener("load", setup);
解决方案
这是因为click
事件冒泡了,并且e.target
是事件所针对的元素(在每个级别上都是相同的元素,实际点击的元素)。因此,当您单击a
元素时,会发生这种情况:
- 处理程序在(元素)上
a
切换类e.target
a
- 单击冒泡到
p
,并且处理程序在(元素)上p
切换类e.target
a
- 单击冒泡到
div
,并且处理程序在(元素)上div
切换类e.target
a
- 单击冒泡到
main
,并且处理程序在(元素)上main
切换类e.target
a
切换偶数次将带您回到开始的位置。:-)
如果在每个级别上,您想引用已附加处理程序的元素,而不是事件所针对的元素,您将使用this
or e.currentTarget
。
这可能有助于使其更清晰:
function setGold(event) {
event.target.classList.toggle("gold");
console.log("event.target.tagName = " + event.target.tagName);
console.log("event.currentTarget.tagName = " + event.currentTarget.tagName);
console.log("this.tagName = " + this.tagName);
}
function setup() {
document.getElementsByTagName("a")[0].addEventListener("click", setGold);
document.getElementsByTagName("p")[0].addEventListener("click", setGold);
document.getElementsByTagName("div")[0].addEventListener("click", setGold);
document.getElementsByTagName("main")[0].addEventListener("click", setGold);
}
window.addEventListener("load", setup);
main {
height: 500px;
width: 900px;
background-color: black;}
div.x (.as-console) {
height: 400px;
width: 700px;
background-color: dimgray;}
p.x {
height: 300px;
width: 500px;
background-color: darkgray;}
a.x {
height: 200px;
width: 300px;
background-color: lightgray;}
.gold {
background-color: gold;}
<main>
<div class="x">
<p class="x">
<a class="x">I'm an a-element.</a>
</p>
</div>
</main>
(我向您的元素和 CSS 添加类的原因是,否则,您的 CSS 会影响 in-snippet 控制台。)
如果您的目标是仅切换被单击的元素,我将利用click
气泡这一事实并仅在 上使用单个处理程序main
,使其切换e.target
的类:
function setGold(event) {
event.target.classList.toggle("gold");
}
function setup() {
document.getElementsByTagName("main")[0].addEventListener("click", setGold);
}
function setGold(event) {
event.target.classList.toggle("gold");
}
function setup() {
document.getElementsByTagName("main")[0].addEventListener("click", setGold);
}
window.addEventListener("load", setup);
main {
height: 500px;
width: 900px;
background-color: black;}
div (.as-console) {
height: 400px;
width: 700px;
background-color: dimgray;}
p {
height: 300px;
width: 500px;
background-color: darkgray;}
a {
height: 200px;
width: 300px;
background-color: lightgray;}
.gold {
background-color: gold;}
<main>
<div>
<p>
<a>I'm an a-element.</a>
</p>
</div>
</main>
如果您想将其过滤为仅 toggle main
、div
、p
和a
而不是 (say) span
,您可以使用Element#matches
来查看元素是否与 CSS 选择器匹配:
function setGold(event) {
if (event.target.matches("a, p, div, main")) {
event.target.classList.toggle("gold");
}
}
function setGold(event) {
if (event.target.matches("a, p, div, main")) {
event.target.classList.toggle("gold");
}
}
function setup() {
document.getElementsByTagName("main")[0].addEventListener("click", setGold);
}
window.addEventListener("load", setup);
main {
height: 500px;
width: 900px;
background-color: black;}
div (.as-console) {
height: 400px;
width: 700px;
background-color: dimgray;}
p {
height: 300px;
width: 500px;
background-color: darkgray;}
a {
height: 200px;
width: 300px;
background-color: lightgray;}
.gold {
background-color: gold;}
<main>
<div>
<p>
<a>I'm an a-element.</a>
<span>I'm a span, I don't toggle</span>
</p>
</div>
</main>
旁注:该load
事件发生在页面加载周期的后期,几乎从来都不是在页面上设置点击处理程序的正确位置。相反,将您的script
标签放在结束标签body
之前</body>
,然后立即进行设置。标记上方的 HTML 定义的所有元素都将在该点存在。更多内容见YUI 指南。
推荐阅读
- javascript - Vue递归组件不渲染
- ios - 如何使用关键帧链接动画
- vba - 循环内循环的更快方法
- c - 循环中计数器不增加?
- flask - 烧瓶内部重定向:url_for 与普通 href?
- android - BottomNavigationView 中的 android 公共方法 setItemIconTintList() 不可用(android studio 4.1,Kotlin)
- laravel - Laravel 8,为什么我必须为我在 routes/web.php 中所做的每一个更改路由:缓存?
- java - jTextArea 没有正确显示文本
- javascript - 输入字段在移动设备上不起作用
- java - Android Recycler 视图禁用滚动条但不使用 setVerticalScrollBarEnabled