代码之家  ›  专栏  ›  技术社区  ›  Alouani Younes

将事件侦听器应用于多个dom元素

  •  3
  • Alouani Younes  · 技术社区  · 8 年前

    我创建了一个JavaScript代码来自动格式化一些日期输入。问题是我的代码只对第一个输入有效,而对其他输入无效。 如何将代码应用于表单中的所有日期输入?

    有没有办法让事件监听器在所有输入上都被激活?

    我想在每个输入和重复代码中添加不同的ID,但这会使代码不可读。

    任何提示,我都试图使用for循环迭代输入,但也不起作用。

    var dates = document.getElementsByTagName('input');
    for (i = 0; i < 3; i++) {
    date = document.getElementsByTagName('input')[i]
    function checkValue(str, max) {
      if (str.charAt(0) !== '0' || str == '00') {
        var num = parseInt(str);
        if (isNaN(num) || num <= 0 || num > max) num = 1;
        str = num > parseInt(max.toString().charAt(0)) && num.toString().length == 1 ? '0' + num : num.toString();
      };
      return str;
    };
    
    date.addEventListener('input', function(e) {
      this.type = 'text';
      var input = this.value;
      if (/\D\/$/.test(input)) input = input.substr(0, input.length - 3);
      var values = input.split('/').map(function(v) {
        return v.replace(/\D/g, '')
      });
      if (values[0]) values[0] = checkValue(values[0], 12);
      if (values[1]) values[1] = checkValue(values[1], 31);
      var output = values.map(function(v, i) {
        return v.length == 2 && i < 2 ? v + ' / ' : v;
      });
      this.value = output.join('').substr(0, 14);
    });
    
    date.addEventListener('blur', function(e) {
      this.type = 'text';
      var input = this.value;
      var values = input.split('/').map(function(v, i) {
        return v.replace(/\D/g, '')
      });
      var output = '';
      
      if (values.length == 3) {
        var year = values[2].length !== 4 ? parseInt(values[2]) + 2000 : parseInt(values[2]);
        var month = parseInt(values[0]) - 1;
        var day = parseInt(values[1]);
        var d = new Date(year, month, day);
        if (!isNaN(d)) {
          document.getElementById('result').innerText = d.toString();
          var dates = [d.getMonth() + 1, d.getDate(), d.getFullYear()];
          output = dates.map(function(v) {
            v = v.toString();
            return v.length == 1 ? '0' + v : v;
          }).join(' / ');
        };
      };
      this.value = output;
    });
    }
    html {
      box-sizing: border-box;
      font-family: 'PT Sans', sans-serif;
    -webkit-font-smoothing: antialiased;
    }
    *, 
    *:before, 
    *:after {
      box-sizing: inherit;
    }
    body {
        background-color: #f3f3f3;
    }
    form {
        width: 100%;
        max-width: 400px;
        margin: 60px auto;
    }
    form input {
        font-size: 30px;
        padding: 0 20px;
        border: 2px solid #ccc;
        width: 100%;
        color: #666;
        line-height: 3;
        border-radius: 7px;
        font-family: 'PT Sans', sans-serif;
        font-weight: bold;
    }
    form input:focus {
        outline: 0;
    }
    form input.error {
        border-color: #ff0000;  
    }
    form label.error {
        background-color: #ff0000;
        color: #fff;
        padding: 6px;
        font-size: 11px;
    }
    
    label {
        color: #999;
        display: block;
        margin-bottom: 10px;
        text-transform: uppercase;
        font-size: 18px;
        font-weight: bold;
        letter-spacing: 0.05em
    }
    form small {
        color: #888;
        font-size: 1em;
        margin-top: 10px;
        display: block;
        align-self: ;
    }
    <form id="form" method="post" action="">
      <label for="amount">Date</label>
      <input type="text" id="date1" />
      <small>Enter date as Month / Day / Year</small>
      </br>
      <label for="amount">Date 2</label>
      <input type="text" id="date2" />
      <small>Enter date as Month / Day / Year</small>
      </br>
      <label for="amount">Date 3</label>
      <input type="text" id="date3" />
      <small>Enter date as Month / Day / Year</small>
      
    </form>

    编辑: 我更正了输入Id,使它们变得唯一。

    编辑2: 在我的解决方案中,我解析输入,并在每个斜杠前后添加空格。I want to eliminate those spaces.为此,我修改了这行:

    this.value = output.join('').substr(0, 14);
    

    我把14换成了10。但这种修改使得删除数据变得不可能。 例如:06/07/无法删除。

    2 回复  |  直到 8 年前
        1
  •  1
  •   CertainPerformance    8 年前

    getElementsBy*方法返回HTMLCollections,这可能很难处理。考虑改用querySelectorAll,它返回一个静态节点列表-与HTMLCollection不同,它可以直接迭代,迭代时不会更改,而且更灵活。

    使用直接迭代每个输入 querySelectorAll('input').forEach 。还要注意,您的HTML无效:文档中不应该有多个具有特定ID的元素。您遗漏了一些HTML,这就是为什么下面的代码段在结尾处会导致错误:

    document.querySelectorAll('input').forEach((date) => {
    
      function checkValue(str, max) {
        if (str.charAt(0) !== '0' || str == '00') {
          var num = parseInt(str);
          if (isNaN(num) || num <= 0 || num > max) num = 1;
          str = num > parseInt(max.toString().charAt(0)) && num.toString().length == 1 ? '0' + num : num.toString();
        };
        return str;
      };
    
      date.addEventListener('input', function(e) {
        this.type = 'text';
        var input = this.value;
        if (/\D\/$/.test(input)) input = input.substr(0, input.length - 3);
        var values = input.split('/').map(function(v) {
          return v.replace(/\D/g, '')
        });
        if (values[0]) values[0] = checkValue(values[0], 12);
        if (values[1]) values[1] = checkValue(values[1], 31);
        var output = values.map(function(v, i) {
          return v.length == 2 && i < 2 ? v + ' / ' : v;
        });
        this.value = output.join('').substr(0, 14);
      });
    
      date.addEventListener('blur', function(e) {
        this.type = 'text';
        var input = this.value;
        var values = input.split('/').map(function(v, i) {
          return v.replace(/\D/g, '')
        });
        var output = '';
    
        if (values.length == 3) {
          var year = values[2].length !== 4 ? parseInt(values[2]) + 2000 : parseInt(values[2]);
          var month = parseInt(values[0]) - 1;
          var day = parseInt(values[1]);
          var d = new Date(year, month, day);
          if (!isNaN(d)) {
            document.getElementById('result').innerText = d.toString();
            var dates = [d.getMonth() + 1, d.getDate(), d.getFullYear()];
            output = dates.map(function(v) {
              v = v.toString();
              return v.length == 1 ? '0' + v : v;
            }).join(' / ');
          };
        };
        this.value = output;
      });
    });
    html {
      box-sizing: border-box;
      font-family: 'PT Sans', sans-serif;
      -webkit-font-smoothing: antialiased;
    }
    
    *,
    *:before,
    *:after {
      box-sizing: inherit;
    }
    
    body {
      background-color: #f3f3f3;
    }
    
    form {
      width: 100%;
      max-width: 400px;
      margin: 60px auto;
    }
    
    form input {
      font-size: 30px;
      padding: 0 20px;
      border: 2px solid #ccc;
      width: 100%;
      color: #666;
      line-height: 3;
      border-radius: 7px;
      font-family: 'PT Sans', sans-serif;
      font-weight: bold;
    }
    
    form input:focus {
      outline: 0;
    }
    
    form input.error {
      border-color: #ff0000;
    }
    
    form label.error {
      background-color: #ff0000;
      color: #fff;
      padding: 6px;
      font-size: 11px;
    }
    
    label {
      color: #999;
      display: block;
      margin-bottom: 10px;
      text-transform: uppercase;
      font-size: 18px;
      font-weight: bold;
      letter-spacing: 0.05em
    }
    
    form small {
      color: #888;
      font-size: 1em;
      margin-top: 10px;
      display: block;
      align-self: ;
    }
    <form id="form" method="post" action="">
      <label for="amount">Date</label>
      <input type="text" id="date" />
      <small>Enter date as Month / Day / Year</small>
      </br>
      <label for="amount">Date 2</label>
      <input type="text" id="date" />
      <small>Enter date as Month / Day / Year</small>
      </br>
      <label for="amount">Date 3</label>
      <input type="text" id="date" />
      <small>Enter date as Month / Day / Year</small>
    
    </form>
        2
  •  1
  •   traktor    8 年前

    通过侦听公共父节点上的事件并仅处理在特定目标上激发的事件,可以以相同的方式处理多个节点上的事件。该方法称为“事件委派”,如中所述 this question 例如,很容易找到额外的讨论和相关问题。

    为了在本例中应用该方法,我将日期处理程序函数声明为命名函数(它们可以内联编写),并添加了 data-type="date" 每个日期输入的属性值,以识别它们(可以找到其他方法),并在它们到达表单元素时检查事件:

    function checkValue(str, max) {
      if (str.charAt(0) !== '0' || str == '00') {
        var num = parseInt(str);
        if (isNaN(num) || num <= 0 || num > max) num = 1;
        str = num > parseInt(max.toString().charAt(0)) && num.toString().length == 1 ? '0' + num : num.toString();
      };
      return str;
    };
      
    function dateInput(date) {  // date is input object argument
      var input = date.value;
      if (/\D\/$/.test(input))
        input = input.substr(0, input.length - 3);
      var values = input.split('/').map(function(v) {
        return v.replace(/\D/g, '')
      });
      if (values[0]) {
        values[0] = checkValue(values[0], 12);
      }
      if (values[1]) {
        values[1] = checkValue(values[1], 31);
      }
      var output = values.map(function(v, i) {
        return v.length == 2 && i < 2 ? v + ' / ' : v;
      });
      date.value = output.join('').substr(0, 14);
    }
    
    function dateBlur(date) {  // date is input object argument
      var input = date.value;
      var values = input.split('/').map(function(v, i) {
        return v.replace(/\D/g, '')
      });
      var output = '';
      if (values.length == 3) {
        var year = values[2].length !== 4 ? parseInt(values[2]) + 2000 : parseInt(values[2]);
        var month = parseInt(values[0]) - 1;
        var day = parseInt(values[1]);
        var d = new Date(year, month, day);
        if (!isNaN(d)) {
          document.getElementById('result').innerText = d.toString();
          var dates = [d.getMonth() + 1, d.getDate(), d.getFullYear()];
          output = dates.map(function(v) {
            v = v.toString();
            return v.length == 1 ? '0' + v : v;
          }).join(' / ');
        }
      }
      date.value = output;
    }
    // delegate event handling from the form element
    
    var form = document.getElementById("form");
    form.addEventListener("blur", function(e) {
      if(e.target.dataset.type == "date") {
        dateBlur(e.target);
      }
    },false);
    form.addEventListener("input", function(e) {
      if(e.target.dataset.type == "date") {
        dateInput(e.target);
      }
    }, false);
    html {
      box-sizing: border-box;
      font-family: 'PT Sans', sans-serif;
    -webkit-font-smoothing: antialiased;
    }
    *, 
    *:before, 
    *:after {
      box-sizing: inherit;
    }
    body {
        background-color: #f3f3f3;
    }
    form {
        width: 100%;
        max-width: 400px;
        margin: 60px auto;
    }
    form input {
        font-size: 30px;
        padding: 0 20px;
        border: 2px solid #ccc;
        width: 100%;
        color: #666;
        line-height: 3;
        border-radius: 7px;
        font-family: 'PT Sans', sans-serif;
        font-weight: bold;
    }
    form input:focus {
        outline: 0;
    }
    form input.error {
        border-color: #ff0000;  
    }
    form label.error {
        background-color: #ff0000;
        color: #fff;
        padding: 6px;
        font-size: 11px;
    }
    
    label {
        color: #999;
        display: block;
        margin-bottom: 10px;
        text-transform: uppercase;
        font-size: 18px;
        font-weight: bold;
        letter-spacing: 0.05em
    }
    form small {
        color: #888;
        font-size: 1em;
        margin-top: 10px;
        display: block;
        align-self: ;
    }
    <form id="form" method="post" action="">
      <label for="amount">Date</label>
      <input type="text" id="date1" data-type="date" />
      <small>Enter date as Month / Day / Year</small>
      </br>
      <label for="amount">Date 2</label>
      <input type="text" id="date2" data-type="date" />
      <small>Enter date as Month / Day / Year</small>
      </br>
      <label for="amount">Date 3</label>
      <input type="text" id="date3" data-type="date" />
      <small>Enter date as Month / Day / Year</small>
      
    </form>