如何用Javascript循环修改值并复制追加div,结合html2pdf导出PDF
问题原因
- 页面仅存在1份合同DOM节点,且节点内所有元素使用全局唯一ID,每次循环赋值都会覆盖上一次的修改结果,最终仅保留最后一个用户的数据
- 没有为每个用户独立克隆生成新的合同节点
解决方案
第一步:修改HTML结构
将原有合同DOM改为隐藏的复用模板,新增容器用于存放所有生成的用户合同:
<div class="container d-flex justify-content-center mt-50 mb-50"> <div class="row"> <div class="col-md-12 text-right mb-3"> <button class="btn btn-primary" id="download">下载pdf</button> </div> <!-- 新增合同容器,所有生成的合同都会放到这里 --> <div class="col-md-12" id="invoice-container"></div> <!-- 隐藏的合同模板,id修改为invoice-template,内部id全部改为class避免重复 --> <div class="card" id="invoice-template" hidden> <div class="card-body ml-3 mr-2 pt-0"> <div class="row justify-content-center"> <h6 style="margin-bottom: 2px;"><strong>Contract <span>№ </span><u class="user_dogovor"></u> </strong> </h6> </div> <div class="row my-row0 nopadding"> <div class="col-md-6" > <p style="float: left; margin-bottom: 5px;">London st</p> </div> <div class="col-md-6"> <p style="float: right; margin-bottom: 5px;">«____» ________________2021 year.</p> </div> </div> <div class="row row-beginning" > <div class="col-sm" > <div class="text-sm-left"> <p>If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators <b><u class="user_name"></u></b>, passport: <b><u class="user_passport"></u></b> given <b><u class="user_vidan_date"></u></b> year given <b><u class="user_kem_vidan"></u></b>, address: <b><u class="user_address"></u></b>, It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable: </p> </div> </div> </div> <div class="row"> <div class="col-sm mydiv-menu"> <div class="text-sm-left"> <p>1.1. There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable </p> <p>1.2 If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text</p> </div> </div> </div> </div> </div> </div> </div>
第二步:修改JS逻辑
循环时克隆模板、填充数据后追加到容器,新增html2pdf下载逻辑:
// 获取模板和容器 const invoiceTemplate = document.getElementById('invoice-template') const invoiceContainer = document.getElementById('invoice-container') // 循环生成每个用户的合同 for (var i = 0; i < rowObject.length; i++) { var counter = rowObject[i]; var name = counter["dogovor_id"]; var passport = counter["passport"]; var kogda_vidan = counter["kogda_vidan"] || '16.02.2021'; // 可根据实际需求替换为从数据中取值 var vidan_date = '«' + kogda_vidan.substring(0,2) + '»' + ' ' + kogda_vidan.substring(3,5) + ' ' + kogda_vidan.substring(6,10); var kem_vidan =counter["kem_vidan"]; var address_dostavki = counter["address"]; var dogovor_id = counter["dogovor_id"] || 153; // 可根据实际需求替换为从数据中取值 // 深克隆模板节点 const newInvoice = invoiceTemplate.cloneNode(true) // 移除隐藏属性 newInvoice.hidden = false // 给当前克隆的合同填充对应数据 newInvoice.querySelector('.user_name').textContent = name newInvoice.querySelector('.user_passport').textContent = passport newInvoice.querySelector('.user_vidan_date').textContent = vidan_date newInvoice.querySelector('.user_kem_vidan').textContent = kem_vidan newInvoice.querySelector('.user_address').textContent = address_dostavki newInvoice.querySelector('.user_dogovor').textContent = dogovor_id // 追加到合同容器 invoiceContainer.appendChild(newInvoice) } // 下载按钮点击逻辑 document.getElementById('download').addEventListener('click', () => { // 配置html2pdf参数,可按需调整 const opt = { margin: 10, filename: '批量合同.pdf', image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: 2 }, jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' } } // 导出整个合同容器的内容 html2pdf().set(opt).from(invoiceContainer).save() })
注意事项
- 克隆模板时必须传入
true参数,才能完整克隆所有子节点 - 填充数据时推荐使用
textContent替代innerHTML,避免XSS安全风险 - 如果合同分页有特殊要求,可以给每个合同节点加上
page-break-after: always;的CSS样式,保证每个合同单独占一页
内容的提问来源于stack exchange,提问作者Abdusoli
相关产品推荐
相关产品推荐

