如何使用HTML、JavaScript、jQuery永久追加动态div 避免表单提交后丢失
问题原因
普通同步表单提交后页面会重新刷新,前端JS动态生成的DOM元素默认不会被服务端渲染到返回的页面里,所以刷新后就会消失。
解决步骤
1. 服务端记录提交的动态项数量
表单提交后,服务端先接收提交的动态字段数组,统计数量,把这个数量和已提交的内容输出到页面的JS变量里,用来做回显:
<?php // 统计提交的服务项数量,默认最少1个 $serviceCount = isset($_POST['sel_services']) ? count($_POST['sel_services']) : 1; // 把每个项的提交值也存下来,用来回显 $submittedServices = $_POST['sel_services'] ?? []; $submittedCare = $_POST['care'] ?? []; $submittedComments = $_POST['comment'] ?? []; ?> <script> // 页面加载时就可以拿到已提交的项数 var existedServiceCount = <?php echo $serviceCount; ?>; // 也可以把已提交的数据转成JSON给前端用 var submittedData = <?php echo json_encode([ 'services' => $submittedServices, 'care' => $submittedCare, 'comments' => $submittedComments ]); ?>; </script>
2. 页面加载完成后自动渲染已有的动态项
把原来生成DOM的逻辑封装成公共函数,页面加载的时候根据existedServiceCount循环调用,把之前用户添加的项都重新渲染出来,同时处理数据回显:
// 封装生成单个服务项的函数 function createServiceItem(index, prefillData = {}) { let szData = '<div class="services-item"><div class="form-group"><div class=" col-xs-12 col-sm-12 col-md-12 col-lg-12">'+ '<input type="checkbox" name="item_index[]" /><select id="sel_box_'+index+'" name="sel_services[]">'; // 下拉框回显逻辑 const serviceOptions = ["Facilities","Housekeeping","Security","Cafeteria","Florist","Delifrance","Pharmacy","Parentcraft Retail","Car"]; serviceOptions.forEach(opt => { const selected = prefillData.services == opt ? 'selected' : ''; szData += `<option value="${opt}" ${selected}>${opt}</option>`; }); szData += '</select></div>'; szData += '<label class=" col-xs-12 col-sm-12 col-md-12 col-lg-12">Please rate your experience.</label>'+ '<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">'; // 单选框回显逻辑 const rateOptions = [ {value: 'Excellent', phpVar: `<?php echo $Others${index}EX ?? '' ?>`}, {value: 'Good', phpVar: `<?php echo $Others${index}GD ?? '' ?>`}, {value: 'Fair', phpVar: `<?php echo $Others${index}FA ?? '' ?>`}, {value: 'Poor', phpVar: `<?php echo $Others${index}PR ?? '' ?>`} ]; rateOptions.forEach(rate => { const checked = prefillData.care == rate.value ? 'checked' : rate.phpVar; szData += `<label class="radio-inline"><input type="radio" name="care[${index}]" value="${rate.value}" ${checked} >${rate.value}</label>`; }); szData += `<?php echo $errorOthers${index} ?? '' ?></div></div><div class="form-group"><label class=" col-xs-12 col-sm-12 col-md-12 col-lg-12">Areas we do well / Areas needing improvement:</label>`+ `<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12"><textarea class="col-xs-12 col-sm-12 col-md-12 col-lg-12" id="comment_${index}" name="comment[${index}]" rows="5" >${prefillData.comment ?? ''}</textarea></div></div></div>`; $("#services").append(szData); } $(document).ready(function() { // 页面加载时先渲染已有的项 let i = existedServiceCount; let j = existedServiceCount; const max = 10; // 替换成你自己设置的最大添加数量 for(let k = 0; k < existedServiceCount; k++) { // 传入对应下标的预填充数据 createServiceItem(k, { services: submittedData.services[k] ?? '', care: submittedData.care[k] ?? '', comment: submittedData.comments[k] ?? '' }); } // 原来的添加按钮逻辑改成调用封装好的函数 $("#add_item").on('click',function(){ if(i < max) { createServiceItem(j); j++; i++; } }); });
3. 修复原有代码的遗留问题
- 动态生成的元素不要用重复id,要给id加上序号后缀,避免DOM选择冲突
- 原来的PHP变量只处理了第1个项的情况,要改成支持多序号的变量,比如
$Others1EX、$Others2EX以此类推
可选简化方案
如果不想改服务端渲染逻辑,可以直接把表单提交改成AJAX异步提交,页面全程不刷新,动态生成的DOM自然就不会丢失。校验失败的话直接在当前页显示错误提示即可,不需要重新加载页面。
内容的提问来源于stack exchange,提问作者field
相关产品推荐
相关产品推荐

