【问题标题】:JavaScript event listener acts differently on label on radio buttonJavaScript 事件侦听器对单选按钮上的标签的作用不同
【发布时间】:2020-09-17 19:20:53
【问题描述】:

我正在尝试将事件侦听器动态添加到 JavaScript 中的一组按钮。但是,只有在单击单选按钮中的实际圆形按钮而不是按钮的标签时,该函数才会正确触发。

function setupRadioBackground(someCard) {
    someCard.querySelectorAll(".form-check-input").forEach((child) => {
        console.log("initial test", someCard);
        child.addEventListener("click", function() {
            console.log(someCard);
            shadeBackground(someCard, child);
        })
    })
}

当函数最初运行时,它会正确显示要添加事件侦听器的卡片,并带有initial test <card here>。但是,当我在匿名事件侦听器函数中记录 someCard 时,会得到不同的结果。如果我单击标签,它会记录 第一个添加了事件侦听器的 someCard。但是,如果我点击圆形按钮,它会记录正确的卡,shadeBackground 功能会正常工作。

有没有办法让标签同样影响正确的卡片?

最小可重现示例

要重现问题,请使用按钮添加两张(或更多)卡片。单击第二张卡的无线电输入和标签。单击无线电输入将正确选择它,而单击标签将选择第一张卡的相应无线电输入。 (使用“整页”按钮,以更好地显示输出。)

const button = document.querySelector("#clickme");
let counter = 0;

button.addEventListener("click", function() {
    const card = document.createElement("div");
    card.className = "card";
    card.id = `demoCard-${counter}`;
    card.innerHTML = `<div class="card-body">
            <h5 class="card-title">Card title</h5>
            <div class="form-check">
                <input class="form-check-input" type="radio" name="exampleRadios" id="exampleRadios1" value="option1" checked>
                <label class="form-check-label" for="exampleRadios1">
                    Default radio
                </label>
            </div>
            <div class="form-check">
                <input class="form-check-input" type="radio" name="exampleRadios" id="exampleRadios2" value="option2">
                <label class="form-check-label" for="exampleRadios2">
                    Second default radio
                </label>
            </div>
        </div>`
       
    document.querySelector(".output").appendChild(card);

    document.querySelector(`#demoCard-${counter}`).querySelectorAll(".form-check").forEach((child) => {
        child.addEventListener("change", function() {
            console.log("you have clicked", child);
        })
    })

    counter += 1;
})
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
    integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
    crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
    integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"
    integrity="sha384-cs/chFZiN24E4KMATLdqdvsezGxaGsi4hLGOzlXwp5UZB1LY//20VyM2taTB4QvJ"
    crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"
    integrity="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm"
    crossorigin="anonymous"></script>

<div class="output">
    <button id="clickme">Click Me</button>
</div>

【问题讨论】:

  • 不应该是change的听众吗? click 通常是实际的鼠标点击事件。虽然 &lt;button&gt; 元素也会触发 click 事件,如果您通过 Enter 或空格按下它。
  • @VLAZ 谢谢你的建议。我已将其更改为 change 侦听器,但仍然存在相同的行为。
  • 如何从 DOM 中选择 someCard
  • 您可以添加snippetminimal reproducible example 吗?由于缺少相应的 HTML,很难看出您的示例中实际发生了什么。
  • @3limin4t0r 这不是可行,而是可验证

标签: javascript dom-events


【解决方案1】:

您的代码中有多个问题:

  1. 您在同一个表单上拥有多个具有相同 ID 的控件。使用以下代码更新卡片的内部 HTML,以便每张卡片具有不同的单选按钮名称和 ID:

    card.innerHTML = `<div class="form-check">
        <input class="form-check-input" type="radio" name="exampleRadios${counter}" id="exampleRadios${counter}_1" value="option1" checked>
        <label class="form-check-label" for="exampleRadios${counter}_1">
            Default radio
        </label>
        </div>
        <div class="form-check">
        <input class="form-check-input" type="radio" name="exampleRadios${counter}" id="exampleRadios${counter}_2" value="option2">
        <label class="form-check-label" for="exampleRadios${counter}_2">
            Second default radio
        </label>
    </div>`
    
  2. 您希望为特定元素添加事件侦听器,而不是一次又一次地添加所有更改事件。变化:

    document.querySelector(`#demoCard-${counter}`).querySelectorAll(".form-check").forEach((child) => {
      addEventListener("change", function() {
        console.log("you have clicked", child);
      })
    })
    

    到:

    document.querySelector(`#demoCard-${counter}`).querySelectorAll(".form-check").forEach((child) => {
      child.addEventListener("change", function() {
        console.log("you have clicked", child);
      })
    })
    

这应该可以解决您的问题。

之后,您的表单将按预期工作:

const button = document.querySelector("#clickme");
let counter = 0;

button.addEventListener("click", function() {
  const card = document.createElement("div");
  card.className = "card";
  card.id = `demoCard-${counter}`;
  card.innerHTML = `<div class="card-body">
            <h5 class="card-title">Card title</h5>
            <div class="form-check">
                <input class="form-check-input" type="radio" name="exampleRadios${counter}" id="exampleRadios${counter}_1" value="option1" checked>
                <label class="form-check-label" for="exampleRadios${counter}_1">
                    Default radio
                </label>
                </div>
                <div class="form-check">
                <input class="form-check-input" type="radio" name="exampleRadios${counter}" id="exampleRadios${counter}_2" value="option2">
                <label class="form-check-label" for="exampleRadios${counter}_2">
                    Second default radio
                </label>
            </div>
        </div>`

  document.querySelector(".output").appendChild(card);

  document.querySelector(`#demoCard-${counter}`).querySelectorAll(".form-check").forEach((child) => {
    child.addEventListener("change", function() {
      console.log("you have clicked", child);
    });
  });

  counter += 1;
})
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js" integrity="sha384-cs/chFZiN24E4KMATLdqdvsezGxaGsi4hLGOzlXwp5UZB1LY//20VyM2taTB4QvJ" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js" integrity="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm" crossorigin="anonymous"></script>

<div class="output">
  <button id="clickme">Click Me</button>
</div>

【讨论】:

    【解决方案2】:

    主要问题是您在运行时重复使用相同的 id

    card.innerHTML = `<div class="card-body">
            <h5 class="card-title">Card title</h5>
            <div class="form-check">
                <input class="form-check-input" type="radio" name="exampleRadios" id="exampleRadios1" value="option1" checked>
                <label class="form-check-label" for="exampleRadios1">
                    Default radio
                </label>
            </div>
            <div class="form-check">
                <input class="form-check-input" type="radio" name="exampleRadios" id="exampleRadios2" value="option2">
                <label class="form-check-label" for="exampleRadios2">
                    Second default radio
                </label>
            </div>
        </div>`
    

    每张新卡都将使用id="exampleRadios1"id="exampleRadios2" 用于他们的收音机。 id 应该是一个标识符,它标识单个元素。浏览器也做了这个假设,所以当你用for="exampleRadios1" 引用id 时,它总是用id="exampleRadios1" 引用第一个元素。

    您可以通过多种方式解决此问题。最简单的方法是不分配 idfor,而是用 &lt;label&gt; 包装 &lt;input&gt;

    card.innerHTML = `<div class="card-body">
            <h5 class="card-title">Card title</h5>
            <div class="form-check">
                <label class="form-check-label">
                    <input class="form-check-input" type="radio" name="exampleRadios" value="option1" checked>
                    Default radio
                </label>
            </div>
            <div class="form-check">
                <label class="form-check-label">
                    <input class="form-check-input" type="radio" name="exampleRadios" value="option2">
                    Second default radio
                </label>
            </div>
        </div>`
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-21
      • 1970-01-01
      • 2012-07-07
      • 2023-01-12
      • 2018-05-12
      • 2013-11-08
      相关资源
      最近更新 更多