【问题标题】:Issue with dynamically created Javascript table动态创建的 Javascript 表的问题
【发布时间】:2016-03-21 20:22:44
【问题描述】:

我最近开始学习 Javascript。我目前正在做一些项目,但遇到了问题。我正在制作联系人管理器页面,其想法是用户输入姓名、电子邮件和电话号码,它们将显示在下面动态创建的 HTML 表格中。有三个按钮。第一个按钮保存信息,第二个按钮清除新用户的输入字段,第三个按钮删除本地存储信息。当您单击表格中的一行时,该行的信息将显示在上面的输入字段中。当您单击 HTML 表中的一行时,一切正常,但是当我单击使用 JavaScript 创建的表中的行时,它不起作用。两个表具有相同的结构、id 和类,但另一个不起作用。 信息表单Javascript显示在dvcontainer div中。

这是代码

(function (){ 

var Person = { 
    Name: "", 
    Email: "", 
    MobileNo: ""
};

var applogic = {
    clearuielements: function () { 
        var inputs = document.getElementsByClassName("c1"); 
        for (i = 0; i < inputs.length; i++) { 
            inputs[i].value = ""; 
        } 
    },
    
    saveitem: function () { 
        var lscount = localStorage.length;
        var inputs = document.getElementsByClassName("c1"); 
            Person.Name = inputs[0].value; 
            Person.Email = inputs[1].value; 
            Person.MobileNo = inputs[2].value; 
            localStorage.setItem("Person_" + lscount, JSON.stringify(Person)); 
            location.reload(); 
    },
    
    loaddata: function () { 
        var datacount = localStorage.length; 
        if (datacount > 0) { 
            var render = "<table id='t_id' border='1'>"; 
            render += "<tr><th>Name</th><th>Email</th><th>Phone</th></tr>"; 
            for (i = 0; i < datacount; i++) { 
                var key = localStorage.key(i);
                var person = localStorage.getItem(key);
                var data = JSON.parse(person);

                render += "<tr><td class='row_s edit_row'>" + data.Name + "</td>"; 
                render += "<td class='row_t'>" + data.Email + "</td>"; 
                render += "<td class='row_d'>" + data.MobileNo + "</td></tr>"; 
            } 
            render+="</table>"; 
            dvcontainer.innerHTML = render; 
        } 
    },
    
    clearstorage: function () { 
        var storagecount = localStorage.length;
        if (storagecount > 0) { 
            for (i = 0; i < storagecount; i++) { 
                localStorage.clear(); 
            } 
        } 
        window.location.reload(); 
    }
};
    
    var btnsave = document.getElementById('btnsave'); 
    btnsave.addEventListener('click', applogic.saveitem, false); 

    var btnclear = document.getElementById('btnclear'); 
    btnclear.addEventListener('click', applogic.clearuielements, false); 

    var btnclearstorage = document.getElementById('btnclearstorage'); 
    btnclearstorage.addEventListener('click', applogic.clearstorage, false); 

    window.onload = function () { 
    applogic.loaddata(); 
    }; 
    
})();

var edit_row = document.querySelectorAll('#t_id .edit_row');
for(var i=0; i<edit_row.length; i++) {
    edit_row[i].addEventListener('click', function(e){
        var tr_parent = this.parentNode;
        document.getElementById('e_site').value = tr_parent.querySelector('.row_s').innerHTML;
        document.getElementById('e_title').value = tr_parent.querySelector('.row_t').innerHTML;
        document.getElementById('e_desc').value = tr_parent.querySelector('.row_d').innerHTML;
    }, false);
}
<!DOCTYPE html>
<html>
    <head>
        <title>nesto</title>
    </head>
    <body>

    <form action="#" method="post" id="edit_form">
        Person Name:<input name="e_site" id="e_site" type="text" class="c1" /><br/>
        Email:<input name="e_title" id="e_title" type="text" class="c1" /><br/>
        Mobile No:<input name="e_desc" id="e_desc" type="text" class="c1"/><br/>
    </form>

    <td><input id="btnsave" type="button" value="Save" /></td> 
    <td><input id="btnclear" type="button" value="Clear" /></td> 
    <td><input id="btnclearstorage" type="button" value="Clear Storage" /></td> 

    <div id="dvcontainer"></div>
     
    
        <!--
        <table id="t_id" border="1">
            <tr>
                <td class="row_s edit_row">yyyy</td>
                <td class="row_t">yyyy</td>
                <td class="row_d">yyyyy</td>
            </tr>
        </table>
        -->
    
        
    <script type="text/javascript" src="funkcije.js"></script>

    </body>
</html>

【问题讨论】:

  • 当我运行 sn-p 时,我没有看到任何表格。
  • 您必须在加载数据时动态添加绑定。
  • 最有可能发生的事情是您在加载另一个表之前将事件侦听器添加到表中。因此,您需要在创建动态表后将事件侦听器添加到动态表中
  • var dvcontainer = document.getElementById("dvcontainer");
  • @John 是的,我现在看到了..不知道为什么,但它在我的电脑上运行良好。

标签: javascript html input html-table


【解决方案1】:

您需要在渲染表格时添加绑定。一种方法是将代码末尾的绑定循环移动到 loaddata 函数中。

这样的事情会起作用:

loaddata: function () { 
        var datacount = localStorage.length; 
        if (datacount > 0) { 
            var render = "<table id='t_id' border='1'>"; 
            render += "<tr><th>Name</th><th>Email</th><th>Phone</th></tr>"; 
            for (i = 0; i < datacount; i++) { 
                var key = localStorage.key(i);
                var person = localStorage.getItem(key);
                var data = JSON.parse(person);

                render += "<tr><td class='row_s edit_row'>" + data.Name + "</td>"; 
                render += "<td class='row_t'>" + data.Email + "</td>"; 
                render += "<td class='row_d'>" + data.MobileNo + "</td></tr>"; 
            } 
            render+="</table>"; 
            dvcontainer.innerHTML = render; 


            //add bindings
            var edit_row = document.querySelectorAll('#t_id .edit_row');
            for(var i=0; i<edit_row.length; i++) {
                edit_row[i].addEventListener('click', function(e){
                    var tr_parent = this.parentNode;
                    document.getElementById('e_site').value = tr_parent.querySelector('.row_s').innerHTML;
                    document.getElementById('e_title').value = tr_parent.querySelector('.row_t').innerHTML;
                    document.getElementById('e_desc').value = tr_parent.querySelector('.row_d').innerHTML;
                }, false);
            }

        } 

在这个 JS Fiddle 中查看完整示例:https://jsfiddle.net/9n8ecmj8/

希望有帮助!

【讨论】:

    【解决方案2】:

    如果向 DOM 添加新元素并希望它们具有事件侦听器,则需要在添加元素后将侦听器添加到元素。

    看起来您正在向脚本加载时存在的元素添加点击事件侦听器,但没有向动态创建的元素添加任何内容。设置点击监听器的代码在 loaddata 函数绑定到 window.onload 之前运行。

    【讨论】:

      【解决方案3】:

      您编写的用于添加侦听器的 for 循环在您的 JavaScript 首次加载时执行,远在您创建任何新表格单元格之前。要在 DOM 元素上注册事件侦听器,该元素必须首先存在,对吗? :)

      您需要做的是称为事件委托。基本上,您在 JavaScript 运行之前在网页上存在的 DOM 元素上连接一个事件侦听器。此 DOM 元素必须是目标元素的父元素。

      在您的情况下,ID 为 "dvcontainer" 的 div 就可以了,因为您在其中呈现表格。首先,我们将选择它:

      var myContainer = document.querySelector('#dvcontainer');
      
      myContainer.addEventListener('click', function(e) {
        //...
      };
      

      如果我们向 myContainer 添加一个事件监听器,它将在对整个 div 的任何点击时调用点击处理函数。我们知道 e.target 选择了被点击的元素,但是有一个有用的方法叫做 ma​​tches 可以告诉我们被选择的元素是否匹配一个选择器字符串(比如“# container”、“.username”,甚至是“h2”)。

      什么是适合您的表格的选择器?为简单起见,让我们使用“td”来处理任何获得点击的表格单元格。这是您的问题的有效解决方案(用此替换您的 for 循环):

      var myContainer = document.querySelector('#dvcontainer');
      
      // adds event listener on myContainer
      myContainer.addEventListener('click', function(e) {
      
        // if the clicked element exists and is a TD element
        if (e.target && e.target.matches('td')) {
      
          // your code from your original for loop
          var tr_parent = e.target.parentNode;
          document.getElementById('e_site').value = tr_parent.querySelector('.row_s').innerHTML;
          document.getElementById('e_title').value = tr_parent.querySelector('.row_t').innerHTML;
          document.getElementById('e_desc').value = tr_parent.querySelector('.row_d').innerHTML;
        }
      }, false);
      

      这种方法的好处是您只需设置一次事件侦听器。无论您使用 JS 动态创建一个、两个还是一千个新的 DOM 元素,它们都将“继承”相同的侦听器和处理程序,而无需即时注册每个元素。

      希望这对您有所帮助!

      更多:

      Vanilla JS 事件委托:https://davidwalsh.name/event-delegate

      element.matches(): https://developer.mozilla.org/en-US/docs/Web/API/Element/matches

      【讨论】:

      • 谢谢,我也试试这个方法。
      • 没问题。告诉我进展如何!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多