动态生成表格行时dateTimePicker崩溃且新增行不生效问题
问题根因
datetimepicker崩溃、新增行组件失效由4个问题直接导致:
- 首行datetimepicker初始化时机错误:若在父容器处于
hidden隐藏状态时初始化组件,DOM无实际渲染尺寸,组件位置、尺寸计算逻辑会直接报错崩溃 - 动态新增行插入DOM后,仅初始化了select2组件,未对新行内的datetimepicker执行初始化,新增行内的input只是原生文本框,无日期选择能力
- 动态生成的删除按钮重复使用id
comments_remove,违反id全局唯一规范,会导致DOM查询、事件绑定异常 - 动态生成的日期选择器外层
.cal-icondiv未写闭合标签,HTML结构错误会干扰组件渲染
修复方案
- 不在元素隐藏状态下初始化UI组件,等表格实际显示后再初始化首行的select2、datetimepicker
- 抽离单行组件初始化逻辑,每次新增行插入DOM后,仅对新行内的组件执行初始化,避免重复初始化已有元素导致报错
- 将重复的id
comments_remove改为class,通过class绑定删除事件 - 补全动态生成HTML里未闭合的标签,修正DOM结构
修正后代码
JS逻辑
$(function() { // 表格显示时初始化首行组件,避免隐藏状态下初始化崩溃 $('#tableshow').on('show', function() { initRowComponents($('#table_achievements_tbody tr')) }) // 页面加载时表格若默认可见,直接初始化首行 if (!$('#tableshow').hasClass('hidden')) { initRowComponents($('#table_achievements_tbody tr')) } $(document).on("click", '.btn-add-row', function() { var table = $(this).closest("table.table-review"); var tableId = table.attr('id'); var newRow = $("<tr />"); newRow.html(GetDynamicTextBox(tableId)); $("#" + tableId + "_tbody").append(newRow); // 仅初始化新插入行的组件,避免重复初始化 initRowComponents(newRow); }); // 用class绑定删除事件,解决id重复问题 $(document).on("click", ".comments_remove", function() { var currentRow = $(this).closest("tr"); var prevRow = currentRow.prev(); if (prevRow.length) { prevRow.find('td:last-child').html('<button type="button" class="btn btn-danger comments_remove"><i class="fa fa-trash-o"></i></button>'); } currentRow.remove(); // 删除后重新排序号 $('#table_achievements_tbody tr').each(function(index) { $(this).find('td:first, th:first').text(index + 1) }) }); // 单行组件初始化通用逻辑 function initRowComponents(row) { row.find('.prodName3, #prodName').select2({width: '289.3px'}); row.find('.varName3, #varName').select2({width: '289.3px'}); // 跳过已经初始化过的datetimepicker,避免重复初始化报错 row.find('.datetimepicker').not('.datetimepicker-loaded').each(function() { $(this).addClass('datetimepicker-loaded').datetimepicker({ format: 'YYYY-MM-DD HH:mm', allowInputToggle: true }) }) } function GetDynamicTextBox(table_id) { var tbody = document.getElementById(table_id).getElementsByTagName("tbody")[0]; var rowsLength = tbody.getElementsByTagName("tr").length + 1; // 补全未闭合的cal-icon标签,删除按钮改用class return '<td>' + rowsLength + '</td>' + '<td><select name="DynamicTextBox" class="select form-control prodName3" value="" style="width:289.3px;"><option>Select</option><option>ProdDolar</option><option>ProdLBP</option><option>Souna</option></select></td>' + '<td><select name="DynamicTextBox" class="select form-control varName3" value="" style="width:289.3px;"><option>Select</option><option>ProdLBPmmm1B3</option></select></td>' + '<td><input type="text" name="DynamicTextBox" class="form-control" value="mm" readonly></td>' + '<td><div class="cal-icon"><input class="form-control floating datetimepicker" name="DynamicTextBox" type="text"></div></td>' + '<td><input type="text" class="form-control" name="DynamicTextBox" onkeyup="javascript:this.value=Comma(this.value);"></td>' + '<td><button type="button" class="btn btn-danger comments_remove"><i class="fa fa-trash-o"></i></button></td>' } });
HTML结构修正
仅需要补全首行日期选择器的未闭合标签即可:
<th> <div class="cal-icon"><input class="form-control floating datetimepicker" type="text"></div> </th>
注意事项
bootstrap-datetimepicker、select2这类UI组件初始化时会读取DOM的实际宽高、位置属性,元素处于display:none隐藏状态时这些属性值为0,直接初始化必然报错,一定要等元素实际渲染到页面后再执行初始化逻辑。
内容的提问来源于stack exchange,提问作者nodedata
相关产品推荐
相关产品推荐

