返回

Edge浏览器打印PDF文件名不正确?2种方法解决

javascript

Edge浏览器打印对话框的文件名问题

在Web应用开发过程中,处理PDF文件展示和打印是常见需求。其中,通过iframe展示PDF并使用浏览器打印功能来实现保存PDF至本地是非常普遍的做法。然而,在Edge浏览器中,打印对话框可能出现一个与预期不符的情况:即使iframe的src属性指向一个具有特定文件名的PDF文件(例如:ExampleDocument.pdf),在Edge的打印对话框中,默认保存的文件名却显示为“index.pdf”。这种不一致的行为会给用户带来困惑,并且影响用户体验。本文探讨产生此问题的根源并提供相应的解决方案。

问题分析

该问题的核心在于Edge浏览器在处理iframe内嵌文档的打印操作时,文件名获取方式与其他浏览器(如Chrome)不同。 Chrome 浏览器倾向于直接使用 iframe src 属性中指定的文件名。 Edge 浏览器则似乎并没有这么直接读取 src 的路径文件名,它会采取一些它认为更通用的方法去读取或猜测这个文件名字,并应用到其打印功能的存储环节。所以直接更改iframe元素的 title 或其他 meta 数据通常不起作用,因为Edge浏览器的默认行为不是从这些数据中读取文件名信息。它可能基于文档的实际URL路径或是页面自身的某些特性,生成最终的文件名。

解决方案

要解决这个Edge浏览器上的文件名问题,以下提供几个可尝试的方案:

1. 使用 Blob URL

此方案的关键是让iframe指向一个Blob对象。我们先将原始PDF文件数据转化成 Blob对象,接着为此 Blob对象创建一个URL,然后让iframe src 指向这个生成的 Blob URL 。由于 Blob 可以包含文件的元信息,这将让 Edge 可以正确解析文件名,打印时也能使用正确文件名。

操作步骤:

  1. 读取PDF文件数据: 通过 XMLHttpRequest (XHR) 获取原始PDF文件数据。
  2. 创建Blob对象: 将XHR的 response 数据(注意要设置为 responseType = 'blob' )传入 Blob() 构造函数生成Blob对象。
  3. 生成Blob URL: 使用 URL.createObjectURL() 为该Blob对象生成一个可用的URL。
  4. 设置iframe src属性: 将此 URL 赋值给iframe的 src 属性。
  5. 执行打印: 在iframe加载完成后,调用其 contentWindow.print()方法触发打印。

代码示例:

function printPDFWithCorrectName(iframeId, pdfUrl, pdfFileName) {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', pdfUrl, true);
  xhr.responseType = 'blob';
  xhr.onload = function () {
    if (xhr.status === 200) {
      const pdfBlob = new Blob([xhr.response], { type: 'application/pdf' });
      const pdfBlobUrl = URL.createObjectURL(pdfBlob);

      const iframe = document.getElementById(iframeId);
      iframe.onload = function(){
        iframe.contentWindow.focus();
        iframe.contentWindow.print();
        URL.revokeObjectURL(pdfBlobUrl);
      }

      iframe.src = pdfBlobUrl;


      
      }else{
        console.error('PDF 文件加载失败:', xhr.status, xhr.statusText)
      }
      
  };
    xhr.onerror = function() {
    console.error('PDF 文件加载时发生错误!');
  };

  xhr.send();
}

// 使用方法
const pdfIframeId = 'iDoc'; // 请替换成你的iframe元素的id
const pdfFileURL = '../../File/TEMP/e42c2279-1363-4d87-933f-625ff20eec7d/ExampleDocument.pdf'; // 请替换为实际的PDF URL
const pdfFileName = 'ExampleDocument.pdf';

printPDFWithCorrectName(pdfIframeId, pdfFileURL, pdfFileName);


  • 请确保修改上述代码中pdfIframeIdpdfFileURLpdfFileName 这三个变量值,将其调整成你的实际情况。

安全性考虑: 记得在 onload 事件触发打印操作后使用 URL.revokeObjectURL()释放先前创建的Blob URL资源, 避免造成内存泄漏。

2. 设置下载链接及打印功能组合使用

如果仅仅需要在本地保存,我们不一定非要调用浏览器打印窗口,通过 <a download> 也可以达到下载pdf文件的目的。 为了保证代码的健壮性,可以将打印窗口逻辑加入,形成一个完整的用户体验流程。

操作步骤:

  1. 创建一个隐藏的 <a> 链接, href 设置为 PDF 文件url,并且设置 download 属性为期待的下载文件名字。
  2. 在触发打印事件前先通过程序触发这个下载链接。
  3. 根据条件调用 print() 逻辑。

代码示例:

<iframe src="../../File/TEMP/e42c2279-1363-4d87-933f-625ff20eec7d/ExampleDocument.pdf#zoom=100&amp;toolbar=0" class="m-3" style="height: 95% !important; width: 99%" frameborder="0" id="iDoc" name="iDoc"></iframe>
<a id="pdfDownloadLink" style="display:none;"></a>
function initiatePDFPrintOrDownload(iframeId, pdfUrl, pdfFileName) {

        const iframe = document.getElementById(iframeId);

        // Create and click the hidden download link.
        const downloadLink = document.getElementById('pdfDownloadLink');
        downloadLink.href = pdfUrl;
        downloadLink.download = pdfFileName;
        downloadLink.click();



      iframe.onload = function(){
        // focus the window for print function
        iframe.contentWindow.focus();
          // delay for the print command is called after the download has start
        setTimeout( function() {iframe.contentWindow.print()}, 200);


      }


}

// 使用方法
const pdfIframeId = 'iDoc'; // 请替换成你的iframe元素的id
const pdfFileURL = '../../File/TEMP/e42c2279-1363-4d87-933f-625ff20eec7d/ExampleDocument.pdf'; // 请替换为实际的PDF URL
const pdfFileName = 'ExampleDocument.pdf';


initiatePDFPrintOrDownload(pdfIframeId, pdfFileURL, pdfFileName);

这种做法保证了下载的文件名符合预期。并且结合浏览器的print函数功能,满足了用户对于“预览打印并本地保存”的双重需求。需要注意的时:为了防止潜在的错误发生,应当在 iframe.onload 中使用 setTimeout 确保 download 事件先于 print 命令执行。

总结

Edge浏览器打印对话框文件名问题源于其内部的文件名解析机制。通过上述方案:利用 Blob URL 或者结合 <a download>和打印API,可以有效地解决文件名问题,提高用户体验。选择方案的时候需要考虑具体需求和系统环境。在处理任何涉及文件操作的流程时,始终要注意安全性,并及时释放资源。