首页 > 解决方案 > 为什么只有所有其他 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);

标签: javascripthtmlevent-handling

解决方案


这是因为click事件冒泡了,并且e.target是事件所针对的元素(在每个级别上都是相同的元素,实际点击的元素)。因此,当您单击a元素时,会发生这种情况:

  • 处理程序在(元素)上a切换类e.targeta
  • 单击冒泡到p,并且处理程序在(元素)上p切换类e.targeta
  • 单击冒泡到div,并且处理程序在(元素)上div切换类e.targeta
  • 单击冒泡到main,并且处理程序在(元素)上main切换类e.targeta

切换偶数次将带您回到开始的位置。:-)

如果在每个级别上,您想引用已附加处理程序的元素,而不是事件所针对的元素,您将使用thisor 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 maindivpa而不是 (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 指南


推荐阅读