解决 :在点击下载事件之前,改变样式,先把滚动区域变成正常的从上到下铺开,完成之后再把样式改回来

  • 如果需要生成的pdf的区域很长,浏览器出现了滚动条,只会下载可视区域内容bug解决
  • 解决 :点击的时候先把滚动条回到0位置就可以

    pdf出现分页时图片文字被截断问题

    解决 :获取所有的需要下载的外层盒子,循环处理这些盒子,获取当前盒子距离顶部的高度offsetTop加上盒子的高度是否大于a4纸的高度,如果大于就在之前插入空白盒子,把内容挤下去。

    dom结构(需要在下载区域的所有外层盒子添加类似于item这样的类名,用于分页截断)

    <div className='content' id='pdfDom'>
        <div className='item'>内容</div>
        <div className='item'>内容</div>
        <!--    每一块dom的class类设置成item(自定义)以此处理内容分割  -->
        <div className='item'>内容</div>
        <div className='item'>内容</div>
    

    组件内编写导出方法exportPDF,(其中isSplit方法判断是否要分割)
    代码如下:

    import jsPDF from 'jspdf'
    import html2canvas from 'html2canvas'
    //避免分页被截断
    const exportPDF = (pdfDom, title) => {
        const A4_WIDTH = 592.28;
        const A4_HEIGHT = 841.89;
        // myLoading 自定义等待动画组件,实现导出事件的异步等待交互
        // dom的id。
        let target = document.getElementById(pdfDom);
        let pageHeight = target.scrollWidth / A4_WIDTH * A4_HEIGHT;
        // 获取分割dom,此处为class类名为item的dom
        let lableListID = target.getElementsByClassName('item');
        // let lableListID = document.getElementsByClassName('item');
        // 进行分割操作,当dom内容已超出a4的高度,则将该dom前插入一个空dom,把他挤下去,分割
        for (let i = 0; i < lableListID.length; i++) {
            let multiple = Math.ceil((lableListID[i].offsetTop + lableListID[i].offsetHeight) / pageHeight);
            if (isSplit(lableListID, i, multiple * pageHeight)) {
                let divParent = lableListID[i].parentNode; // 获取该div的父节点
                let newNode = document.createElement('div');
                newNode.className = 'emptyDiv';
                newNode.style.background = '#01195e';
                let _H = multiple * pageHeight - (lableListID[i].offsetTop + lableListID[i].offsetHeight);
                newNode.style.height = _H + 30 + 'px';
                newNode.style.width = '100%';
                let next = lableListID[i].nextSibling; // 获取div的下一个兄弟节点
                // 判断兄弟节点是否存在
                // console.log(next);
                if (next) {
                    // 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
                    divParent.insertBefore(newNode, next);
                } else {
                    // 不存在则直接添加到最后,appendChild默认添加到divParent的最后
                    divParent.appendChild(newNode);
        pdf(pdfDom, title);
    // 判断是否需要添加空白div
    const isSplit = (nodes, index, pageHeight) => {
        // 计算当前这块dom是否跨越了a4大小,以此分割
        if (nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight) {
            return true;
        return false;
    const pdf = (pdfDom, title) => {
        // 避免出现浏览器滚动条导致的内容不全处理
        document.body.scrollTop = document.documentElement.scrollTop = 0
        //div内部滚动导致内容不全处理
        // document.getElementById('app').style.height = 'auto';
        setTimeout(() => {
            html2canvas(document.getElementById(pdfDom), {
                allowTaint: true,
                scale: 3,  // 按比例增加分辨率
                dpi: 300,  // 分辨率
                // height: document.getElementById('upload').scrollHeight,
                // windowHeight: document.getElementById('upload').scrollHeight
            }).then(canvas => {
                var contentWidth = canvas.width;
                var contentHeight = canvas.height;
                //一页pdf显示html页面生成的canvas高度;
                var pageHeight = contentWidth / 592.28 * 841.89;
                //未生成pdf的html页面高度
                var leftHeight = contentHeight;
                //页面偏移
                var position = 0;
                //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
                var imgWidth = 595.28;
                var imgHeight = 592.28 / contentWidth * contentHeight;
                var pageData = canvas.toDataURL('image/jpeg', 1.0);
                var pdf = new jsPDF('', 'pt', 'a4');
                //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
                //当内容未超过pdf一页显示的范围,无需分页
                if (leftHeight < pageHeight) {
                    pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
                } else {
                    while (leftHeight > 0) {
                        pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
                        leftHeight -= pageHeight;
                        position -= 841.89;
                        //避免添加空白页
                        if (leftHeight > 0) {
                            pdf.addPage();
                pdf.save(`${title}.pdf`);
        }, 300)
    const contentRender = () =>{
      return <>
        // item等内容
    return (
          <Button key="exportPDF" type="primary" loading={pdfLoading} onClick={() => exportPDF('pdfDom', '文件标题')}>
            导出PDF
          </Button>       
          {/* 打印及预览dom */}
          <div className={styles.pageContainer}>
            <div ref={printRef} >
              {contentRender()}
          {/* pdf导出dom */}
          <div id='pdfDom' className={`${styles.pageContainer} ${styles.noDownload}`} >
            {contentRender()}
    

    css代码

    .pageContainer {
        position: relative;
        margin: auto;
        padding: 48px;
        // 预览时候的宽度需要和打印时算上内边距后的正文宽度保持一致
        // 不然会导致计算页码时出现误差
        width: 700px;
        background-color: white;
        font-family: SimSun;
    .noDownload {
        position: absolute;
        top: 0;
        z-index: -1;
    

    以上js代码中,'打印及预览dom'是用于打印预览的(可忽略),所以此处将 pdf下载用的dom复制了一份,设置css .noDownload 隐藏(仅用于下载pdf,不展示给用户)