【问题标题】:How to change the value of an element using EventListener如何使用 EventListener 更改元素的值
【发布时间】:2019-06-20 22:35:13
【问题描述】:

在这个程序中,我可以使用按钮添加输入,但我需要在每个输入发生变化时显示其长度。我可以使用 EventListener 获得长度,但我不确定如何更改任何新创建的按钮的文本值。

在第 12 行,您可以看到我能够在第一个输入上成功更改值,但我使用的是 html 变量。如果您查看我的 addCell() 函数,您会发现我有一个元素作为每个节点的子节点,以跟踪每个输入的长度。我需要在我的 change() 函数中访问该元素,以便将 event.target.value.length 设置为相应的节点子元素。

我尝试过使用它,设置 var x = this,我尝试过使用 event.target 属性来查找相应的节点,甚至是 innerHTML。

var i = 0;
var count = 1;
var length = 2;
var chars = 0;

document.addEventListener('input', function (evt) {
  change(evt);
});

function change(elem) {
  var check = document.getElementById("first");
  if (event.target == check) {
    document.getElementById("len").innerHTML = event.target.value.length;
    return;
  }

  // Here's where I'm stuck

}

function removeCell() {
  if (count <= 1) {
    alert("Illegal operation, the police have been notified.")
    return;
  }
  var elem = document.getElementById('main');
  elem.removeChild(elem.lastChild);
  count = count - 1;
  length = length - 1;
}

function addCell() {
  var node = document.createElement('div');
  node.innerHTML += length;
  var inp = document.createElement('INPUT');
  var size = document.createElement('size');

  inp.setAttribute("type", "text");
  node.appendChild(inp);
  node.appendChild(size);
  document.getElementById('main').appendChild(node);

  count += 1;
  length += 1;
  i += 1;
}
#area {
  width: 585px;
  background-color: lightgrey;
  color: black;
  border-style: solid;
  margin-left: auto;
  margin-right: auto;
  min-height: 100px;
  height: auto
}
#texts {
  width: 220px;
  height: 50px;
  border-style: solid;
}
body {
  background-color: grey;
}
<div id="area">
  <form id="main">
    <pre><b>          input </b>          length</pre>
    <span id="list">
      1<input type="text" id="first"> <var id="len"></var>
    </span>

  </form>
  <br />
  <button onclick="addCell()">Add Cell</button>
  <button onclick="removeCell()">Remove Cell</button>
  <button onclick="sort()">Sort</button>
</div>

由于我能够使用 alert() 来显示每个新创建的输入在每次更改时的正确长度,我知道有一种方法可以访问我创建的“size”元素以使用 event.target 对其进行更新.value.length

【问题讨论】:

    标签: javascript html


    【解决方案1】:

    您的问题是您使用“全局”输入事件侦听器,而您的 change() 函数未编程为处理多个输入字段,因为您在其中查询已知元素 ID firstlen

    如果您想使用全局侦听器,您必须告诉您的 change() 函数如何访问新的输入和相应的目标字段。

    更简单的方法是修改 addCell() 函数并将事件侦听器附加到您正在创建的输入字段,而不是使用全局侦听器。因此,每个输入字段都拥有自己的事件侦听器。由于输入字段和显示输入值长度的 size 元素都是在同一范围内创建的,因此您可以轻松地将长度写入相应的 size 元素。

    inp.addEventListener('input', function(){
      size.innerText = inp.value.length;
    });
    

    如果您希望它与您提供的 HTML 一起使用,您需要删除您的第一个输入字段并手动调用 addCell() 以便呈现您的初始输入。

    您的代码应该如下所示(注意:我设置了var count = 0;var length = 1;):

    var i = 0;
    var count = 0;
    var length = 1;
    var chars = 0;
    
    function removeCell() {
      if (count <= 1) {
        alert("Illegal operation, the police have been notified.")
        return;
      }
      var elem = document.getElementById('main');
      elem.removeChild(elem.lastChild);
      count = count - 1;
      length = length - 1;
    }
    
    function addCell() {
      var node = document.createElement('div');
      node.innerHTML += length;
      var inp = document.createElement('INPUT');
      var size = document.createElement('size');
    
      inp.setAttribute("type", "text");
      inp.addEventListener('input', function(){
        size.innerText = inp.value.length;
      });
      node.appendChild(inp);
      node.appendChild(size);
      document.getElementById('main').appendChild(node);
    
      count += 1;
      length += 1;
      i += 1;
    }
    
    addCell();
    #area {
      width: 585px;
      background-color: lightgrey;
      color: black;
      border-style: solid;
      margin-left: auto;
      margin-right: auto;
      min-height: 100px;
      height: auto
    }
    #texts {
      width: 220px;
      height: 50px;
      border-style: solid;
    }
    body {
      background-color: grey;
    }
    <div id="area">
      <form id="main">
        <pre><b>          input </b>          length</pre>
        <span id="list"></span>
      </form>
      <br />
      <button onclick="addCell()">Add Cell</button>
      <button onclick="removeCell()">Remove Cell</button>
      <button onclick="sort()">Sort</button>
    </div>

    【讨论】:

    • 我感觉我的设置有点不对劲,你设置 addCell() 函数的方式更有意义。在创建节点时直接将事件监听器添加到输入中,看起来非常优雅,省去了很多麻烦。非常感谢!
    【解决方案2】:
      1234563在处理多个标签时使用#id 是困难且不必要的。以防万一您不知道这条关键规则:#ids 必须是唯一的,同一页面上不能有任何重复的#ids。重复的 #ids 将在 90% 的情况下破坏 JavaScript/jQuery。
    • 要通过.class#id[name]tagName 等访问标签,对多个标签使用document.querySelector()document.querySelectorAll()

    • 要通过[name]#id 访问表单和表单控件(输入、输出、选择等),请使用HTMLFormElement and HTMLFormControlsCollection APIs

    • .innerHTML 具有破坏性,因为它会覆盖标签中的所有内容。 .insertAdjacentHTML() 是非破坏性的,可以将 htmlString 放置在标签内或标签周围的 4 个不同位置。

    • 事件处理程序和事件侦听器仅适用于页面加载时最初位于页面上的标签。之后动态添加的任何标签都无法注册以侦听/处理事件。您必须通过注册自页面加载以来一直存在于页面上的祖先标记来委派事件。这是使用delRow() 完成的,因为按钮是在每一行上动态创建的(更改它是因为删除最后一行的一个删除按钮没有那么有用。例如 7 行,您需要删除 4 行才能到达第三行)。

    • 下面是一个细分:[...ui.len]ui 引用所有表单控件.len 是所有带有[name=len] 的标签。方括号和 spread operator 将 len 标签的集合转换为数组。

    • 没有&lt;size&gt;&lt;/size&gt; 这样的东西。所以document.createElement('size')是非常错误的。

    const main = document.forms.main;
    
    main.oninput = count;
    main.elements.add.onclick = addRow;
    document.querySelector('tbody').onclick = delRow;
    
    function count(e) {
      const active = e.target;
      const ui = e.currentTarget.elements;
      const row = active.closest('tr');
      const idx = [...row.parentElement.children].indexOf(row);
      const length = [...ui.len][idx];
      length.value = active.value.length;
      return false;
    }
    
    function addRow(e) {
      const tbody = document.querySelector('tbody');
      let last = tbody.childElementCount+1;
      tbody.insertAdjacentHTML('beforeend', `<tr><td data-idx='${last}'><input name='txt' type="text"></td><td><output name='len'>0</output></td><td><button class='del' type='button'>Delete</button></td>`);
      return false;
    }
    
    function delRow(e) {
      if (e.target.matches('.del')) {
        const row = e.target.closest('tr');
        let rows = [...row.parentElement.children];
        let qty = rows.length;
        let idx = rows.indexOf(row);
        for (let i = idx; i < qty; i++) {
          rows[i].querySelector('td').dataset.idx = i;
        }
        row.remove();
      }
      return false;
    }
          
        
        
    body {
      background-color: grey;
    }
    
    #main {
      width: 585px;
      background-color: lightgrey;
      color: black;
      border-style: solid;
      margin-left: auto;
      margin-right: auto;
      min-height: 100px;
      height: auto
    }
    
    tbody tr td:first-of-type::before {
      content: attr(data-idx)' ';
    }
    <form id="main">
      <table>
        <thead>
          <tr>
            <th class='txt'>input</th>
            <th class='len'>length</th>
            <th><button id='add' type='button'>Add</button></th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td data-idx='1'><input name='txt' type="text"></td>
            <td><output name='len'>0</output></td>
            <td><button class='del' type='button'>Delete</button></td>
          </tr>
        </tbody>
      </table>
      <!--These are dummy nodes because of the
      HTMLFormControlsCollection API ability to use id or name, there
      must be at least 2 tags with the same name in order for it to
      be considered iterable-->
      <input name='txt' type='hidden'>
      <input name='len' type='hidden'>
    </form>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-18
      • 2022-06-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多