【问题标题】:unable to make AJAX call from jsPDF fromHTML无法从 HTML 的 jsPDF 进行 AJAX 调用
【发布时间】:2020-01-25 17:27:45
【问题描述】:

我有一个简单的结构,可以从 jsPDF 生成 PDF,获取“datauristring”并将其传递给 AJAX 请求。但是,AJAX 方法不会触发。当它尝试“发送”时,它会抛出异常“h 未定义”。我从跟踪 XHR 请求中发现了这一点,它出现在 jQuery 库中。 jsPDF回调后这么快就不能触发AJAX请求了吗?

我应该注意我正在将 PDF 发送到一个服务,该服务将该 pdf 与另一个 pdf 合并并返回一个全新的文档。

var docX = new jsPDF("p", "pt", "letter");
margins = {
    top: 20,
    bottom: 20,
    left: 20,
    width: 522
};
specialElementHandlers = {
  // element with id of "bypass" - jQuery style selector
  '#bypassme': function (element, renderer) {
      // true = "handled elsewhere, bypass text extraction"
      return true
  }
};
docX.fromHTML (
    document.getElementById('productModalContent'),
    margins.left,
    margins.top, {
        'width' : margins.width,
        'elementHandlers': specialElementHandlers
    },
    function (dispose) {
        specDoc = (docX.output('datauristring'));
        console.log(dispose);
        //docX.save('asdfas.pdf');
        //console.log(specDoc);
        processPDF(specDoc);
    }, margins
);  
function processPDF(doc) {
  console.log(doc.length);

  $.ajax({
      type: "POST",
      url: "https://someurl",
      data: {
          'partNumber' : '$!{rawPartNumber}',
          'region' : '$!{regionContentlet.code}',
          'doc' : doc
      },
      cache: false,
      success: function(data) {
          console.log("success?");
          var link=document.createElement('a');
          link.href='data:application/pdf;base64,' + data;
          link.download="myfile.pdf";
          link.setAttribute('target', '_blank');
          link.click();
      },
      error: function(data) {
          console.log(data); 
      }
  });

}

编辑:删除 ajax 并添加 fetch。

const response = await fetch('myurl', {
        method: 'POST',
        body: {
            'partNumber' : '$!{rawPartNumber}',
            'region' : '$!{regionContentlet.code}',
            'myDiv' : doc
        }
    });

【问题讨论】:

  • 乍一看,我能在 jsPDF 库中找到变量 h 的唯一地方是 rect 和 rectRounded 函数。这是有道理的,这是由渲染函数内部某处的 fromHTML() 调用的。但是,当我查看 fromHTML() github.com/willowsystems/jsPDF/blob/master/… 的来源时,它只接受 4 个参数,而不是 6 个。那么您使用的是哪个版本的 jsPDF?因为如果您期望 6 个参数,我可能正在查看错误的库或您的函数 processPDF 根本没有使用。
  • 您收到console.log("success?");console.log(data); 还是在此之前收到错误?您是否尝试过使用 fetch() 请求而不是 jquery 来避免该问题?
  • 这些都没有出现,这很奇怪。就像 jQuery 没有冒泡一样。我还没试过 fetch
  • 我无法重现该问题。我将您的代码复制到一个空的 html 页面的

标签: javascript ajax jspdf


【解决方案1】:

对于任何可能被这个问题停下来的人,我确实解决了我的问题。我无法让 AJAX 调用从 jsPDF 的 fromHTML 函数中工作。我最终将第一个 PDF 作为 base64 字符串,然后调用 jsPDF 的 fromHTML 获取第二个 PDF 数据集,最后使用 pdf-lib 将两个 PDF 拼接在一起,全部在 js 中。

<script src="https://unpkg.com/jspdf@latest/dist/jspdf.min.js"></script>
<script src="https://unpkg.com/pdf-lib/dist/pdf-lib.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.js"></script>
<script>

async function processPDF() {

    $.ajax({
        type: "POST",
        url: 'mypdfurl',
        data: {

        },
        cache: false,
        success: function(data) {
            console.log("success?");
            var docX = new jsPDF("p", "pt", "letter");
                margins = {
                top: 20,
                bottom: 20,
                left: 20,
                width: 575,             
                };
                specialElementHandlers = {
                    // element with id of "bypass" - jQuery style selector
                    '#bypassme': function (element, renderer) {
                        // true = "handled elsewhere, bypass text extraction"
                        return true
                    },
                    '.info': function (element, renderer) {
                        element.style.fontSize = "12px";
                    },
                    '.spec': function (element, renderer) {
                        element.style.fontSize = "12px";
                    },
                    '.attribute': function (element, renderer) {
                        element.style.fontSize = "12px";
                    },
                    '#logoProductPrint': function(element, renderer) {
                        var ele = element.firstElementChild;
                        ele.setAttribute("style", "width:80px;height:50px");                            
                    },

                };
            var itm = document.getElementById('productPrint');
            var itm_p = itm.cloneNode(true);
            synchronizeCssStyles(itm, itm_p, true);

            docX.fromHTML (
                //document.getElementById('productPrint'),
                itm_p,
                margins.left,
                margins.top, 
                {
                    'width' : margins.width,
                    'elementHandlers': specialElementHandlers,
                },
                async function (dispose) {
                    var specDoc = (docX.output('datauristring'));

                    const pdfDoc = await PDFLib.PDFDocument.create();
                    var d = 'data:application/pdf;base64,' + data;
                    const firstDoc = await PDFLib.PDFDocument.load(d);
                    const secondDoc = await PDFLib.PDFDocument.load(specDoc);

                    const firstPage = await pdfDoc.copyPages(firstDoc, [0]);
                    pdfDoc.addPage(firstPage[0]);
                    const secondPage = await pdfDoc.copyPages(secondDoc, [0]);

                    pdfDoc.addPage(secondPage[0]);
                    const pdfBytes = await pdfDoc.save();


                    const blob = new Blob([pdfBytes], { type: 'application/pdf' });
                    const blobUrl = URL.createObjectURL(blob);

                    var link=document.createElement('a');
                    link.href=blobUrl;

                    link.setAttribute('target', '_blank');
                    link.click();

                }, margins
            );     


        },
        error: function(data) {
            console.log(data); 
        }
    });

    function synchronizeCssStyles(src, destination, recursively) {

    // if recursively = true, then we assume the src dom structure and destination dom structure are identical (ie: cloneNode was used)

    // window.getComputedStyle vs document.defaultView.getComputedStyle 
    // @TBD: also check for compatibility on IE/Edge 
    destination.style.cssText = document.defaultView.getComputedStyle(src, "").cssText;

    if (recursively) {
        var vSrcElements = src.getElementsByTagName("*");
        var vDstElements = destination.getElementsByTagName("*");

        for (var i = vSrcElements.length; i--;) {
            var vSrcElement = vSrcElements[i];
            var vDstElement = vDstElements[i];
//          console.log(i + " >> " + vSrcElement + " :: " + vDstElement);
            vDstElement.style.cssText = document.defaultView.getComputedStyle(vSrcElement, "").cssText;
        }
      }
    }
}

【讨论】:

    【解决方案2】:

    您不能使用第一个方法的原因是 b/c 您必须将其作为 blob 获取,因此 jQuery 或 xhr 不会尝试将二进制数据编码为文本。这样你就会得到损坏的数据。 您需要将其作为原始数据获取。 jQuery 在这个 b/c 方面表现不佳,您无法将 responsetype 更改为 blob。所以你需要自己写xhr请求或者使用fetch apifetch(url).then(r =&gt; r.blob()).then(code)

    但如果我在你那里我应该从 base64 恢复到原始二进制文件以保存数据并使用(可能是隐藏的)&lt;from method="https://someurl" hidden&gt; 使用正确的响应标头下载 pdf

    【讨论】:

    • 我也尝试了获取请求,但仍然无法正常工作。我确实得到了不同的行为,但是我将 pdf 数据从 jsPDF 发送到后端的 PDF 数据没有填充。抱歉,这不是一个很好的解释。关于原始二进制数据的有趣点我没有尝试过。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-10
    • 2013-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多