如何用JavaScript获取分页列表中所有页面的li元素并导出PDF
如何导出分页卡片列表的所有项为PDF?
我有一个带分页功能的卡片区域,本质是无序列表(ul)中的<li>元素。因为<li>数量多,设置了分页,用户可点击next按钮切换查看。现在想获取所有列表项并导出为PDF,但当前JavaScript代码只能打印第一页,请问怎么实现获取多页的<li>元素?
现有代码
HTML代码
<ul class="a-CardView-items a-CardView-items--grid2col LAYOUT-CLASS col-sm-12 mb-3"> <li class="a-CardView-item col-sm-6" data-id="4" data-rownum="1"> <div class="a-CardView has-title has-subtitle has-body has-secondary has-badge has-media has-media--body has-media--square has-media--cover CARD-CLASS"> <div class="a-CardView-media a-CardView-media--body a-CardView-media--square a-CardView-media--cover MEDIA-CLASS"> <img class="a-CardView-mediaImg" src="https://images.pexels.com/photos/1407305/pexels-photo-1407305.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="Photo of Fms" loading="lazy"> </div> <div class="a-CardView-header"> <div class="a-CardView-headerBody"> <h3 class="a-CardView-title TITLE-CLASS">Fr Ad</h3> <h4 class="a-CardView-subTitle SUBTITLE-CLASS">test4@gmail.com</h4> </div> <div class="a-CardView-badge BADGE-CLASS" title="C 133"> <span class="a-CardView-badgeLabel">Class</span> <span class="a-CardView-badgeValue">133</span> </div> </div> <div class="a-CardView-body"> <div class="a-CardView-mainContent"> <div class="a-CardView-mainContent BODY-CLASS chip item-status" key="4"></div> </div> <div class="a-CardView-subContent BODY-CLASS chip">New Candidates</div> </div> </div> </li> <li class="a-CardView-item col-sm-6" data-id="48" data-rownum="2"> <div class="a-CardView has-title has-subtitle has-body has-secondary has-badge has-media has-media--body has-media--square has-media--cover CARD-CLASS"> <div class="a-CardView-media a-CardView-media--body a-CardView-media--square a-CardView-media--cover MEDIA-CLASS"> <img class="a-CardView-mediaImg" src="https://images.pexels.com/photos/1407305/pexels-photo-1407305.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="Photo ena" loading="lazy"> </div> <div class="a-CardView-header"> <div class="a-CardView-headerBody"> <h3 class="a-CardView-title TITLE-CLASS">Jo Ba</h3> <h4 class="a-CardView-subTitle SUBTITLE-CLASS">test3@gmail.com</h4> </div> <div class="a-CardView-badge BADGE-CLASS" title="C 133"> <span class="a-CardView-badgeLabel">Class</span> <span class="a-CardView-badgeValue">133</span> </div> </div> <div class="a-CardView-body"> <div class="a-CardView-mainContent"> <div class="a-CardView-mainContent BODY-CLASS chip item-status" key="48"></div> </div> <div class="a-CardView-subContent BODY-CLASS chip">New Candidates</div> </div> </div> </li> </ul>
JavaScript代码
var btn = document.getElementById("print_btn"); //var createpdf = document.getElementsByClassName('LAYOUT-CLASS'); var createpdf = document.getElementById('export_candidates_Cards'); //var createpdf = document.querySelectorAll('.a-CardView-item '); //var number_of_card = document.getElementById('test').getAttribute('pageLength'); console.log(createpdf); var opt = { margin: 0, filename: 'Candiates.pdf', html2canvas: { scale: 2 }, jsPDF: { unit: 'in', format: 'A4', orientation: 'portrait' }, pagebreak: { mode: ['avoid-all', 'css', 'legacy'] } }; html2pdf().set(opt).from(createpdf).save();
解决方案
方法1:临时拼接所有卡片到隐藏容器再导出
核心思路是模拟加载所有分页的卡片,把它们放到一个临时的隐藏DOM容器里,再用html2pdf导出这个容器,导出完成后销毁临时容器。
document.getElementById("print_btn").addEventListener("click", async function() { // 创建临时容器 const tempContainer = document.createElement('ul'); tempContainer.className = 'a-CardView-items a-CardView-items--grid2col LAYOUT-CLASS col-sm-12 mb-3'; tempContainer.style.position = 'absolute'; tempContainer.style.top = '-9999px'; tempContainer.style.left = '-9999px'; document.body.appendChild(tempContainer); try { // 替换成实际总页数 const totalPages = 5; // 替换成你的next按钮选择器 const nextBtn = document.querySelector('.pagination-next-btn'); // 克隆当前页卡片到临时容器 const currentItems = document.querySelectorAll('.a-CardView-item'); currentItems.forEach(item => tempContainer.appendChild(item.cloneNode(true))); // 循环切换分页,克隆每一页卡片 for (let i = 1; i < totalPages; i++) { nextBtn.click(); // 等待页面渲染完成,可根据实际情况调整等待时间 await new Promise(resolve => setTimeout(resolve, 500)); const pageItems = document.querySelectorAll('.a-CardView-item'); pageItems.forEach(item => tempContainer.appendChild(item.cloneNode(true))); } // 导出PDF const opt = { margin: 0, filename: 'Candiates.pdf', html2canvas: { scale: 2 }, jsPDF: { unit: 'in', format: 'A4', orientation: 'portrait' }, pagebreak: { mode: ['avoid-all', 'css', 'legacy'] } }; await html2pdf().set(opt).from(tempContainer).save(); } catch (err) { console.error('导出失败:', err); } finally { // 销毁临时容器 document.body.removeChild(tempContainer); } });
方法2:直接从数据源渲染所有卡片
如果分页数据是从接口获取的,最优方案是直接请求所有数据,渲染一个包含所有卡片的隐藏列表再导出,避免DOM切换的等待问题。
document.getElementById("print_btn").addEventListener("click", async function() { // 创建临时容器 const tempContainer = document.createElement('ul'); tempContainer.className = 'a-CardView-items a-CardView-items--grid2col LAYOUT-CLASS col-sm-12 mb-3'; tempContainer.style.position = 'absolute'; tempContainer.style.top = '-9999px'; tempContainer.style.left = '-9999px'; document.body.appendChild(tempContainer); try { // 请求所有数据,替换成你的实际接口 const response = await fetch('/api/get-all-candidates'); const allCandidates = await response.json(); // 遍历数据渲染所有卡片 allCandidates.forEach(candidate => { const li = document.createElement('li'); li.className = 'a-CardView-item col-sm-6'; li.dataset.id = candidate.id; li.dataset.rownum = candidate.rownum; li.innerHTML = ` <div class="a-CardView has-title has-subtitle has-body has-secondary has-badge has-media has-media--body has-media--square has-media--cover CARD-CLASS"> <div class="a-CardView-media a-CardView-media--body a-CardView-media--square a-CardView-media--cover MEDIA-CLASS"> <img class="a-CardView-mediaImg" src="${candidate.imageUrl}" alt="${candidate.name}" loading="lazy"> </div> <div class="a-CardView-header"> <div class="a-CardView-headerBody"> <h3 class="a-CardView-title TITLE-CLASS">${candidate.name}</h3> <h4 class="a-CardView-subTitle SUBTITLE-CLASS">${candidate.email}</h4> </div> <div class="a-CardView-badge BADGE-CLASS" title="C ${candidate.classNum}"> <span class="a-CardView-badgeLabel">Class</span> <span class="a-CardView-badgeValue">${candidate.classNum}</span> </div> </div> <div class="a-CardView-body"> <div class="a-CardView-mainContent"> <div class="a-CardView-mainContent BODY-CLASS chip item-status" key="${candidate.id}"></div> </div> <div class="a-CardView-subContent BODY-CLASS chip">${candidate.status}</div> </div> </div> `; tempContainer.appendChild(li); }); // 导出PDF const opt = { margin: 0, filename: 'Candiates.pdf', html2canvas: { scale: 2 }, jsPDF: { unit: 'in', format: 'A4', orientation: 'portrait' }, pagebreak: { mode: ['avoid-all', 'css', 'legacy'] } }; await html2pdf().set(opt).from(tempContainer).save(); } catch (err) { console.error('导出失败:', err); } finally { document.body.removeChild(tempContainer); } });
方法3:临时取消分页显示所有卡片
如果分页是通过CSS类控制显示隐藏的,可以临时移除分页控制类,显示所有卡片后导出,导出完成再恢复原状态。
document.getElementById("print_btn").addEventListener("click", async function() { const listContainer = document.querySelector('.LAYOUT-CLASS'); // 保存原有的分页相关类 const originalClasses = listContainer.className; // 移除分页控制类,替换成你的实际分页控制类 listContainer.classList.remove('pagination-controlled'); try { // 等待DOM更新 await new Promise(resolve => setTimeout(resolve, 300)); // 导出当前容器 const opt = { margin: 0, filename: 'Candiates.pdf', html2canvas: { scale: 2 }, jsPDF: { unit: 'in', format: 'A4', orientation: 'portrait' }, pagebreak: { mode: ['avoid-all', 'css', 'legacy'] } }; await html2pdf().set(opt).from(listContainer).save(); } catch (err) { console.error('导出失败:', err); } finally { // 恢复原有的类 listContainer.className = originalClasses; } });
内容的提问来源于stack exchange,提问作者qka
相关产品推荐
相关产品推荐

