safari不允许第二个window.print()

时间:2018-01-30 15:14:28

标签: javascript html printing safari

您好我在Safari中遇到了一个奇怪的问题。我有一个按钮,当点击它打印html的内容。我的问题是,当第一次调用window.print()时效果很好,但是,在第二次点击时,它会显示一个弹出窗口说明:

  

'此网页正在尝试打印。你想打印这个网页吗?'

如果我在此对话框中单击打印,则不会发生任何事情。任何想法为什么会发生这种情况?提前谢谢!

Javascript -

$scope.print = function() {
    var contents = document.getElementById("print-section").outerHTML;
    var frame1 = document.createElement('iframe');
    frame1.name = "frame3";
    frame1.style.position = "absolute";
    frame1.style.top = "-1000000px";
    document.body.appendChild(frame1);

    var frameDoc = frame1.contentWindow ? frame1.contentWindow : frame1.contentDocument.document ? frame1.contentDocument.document : frame1.contentDocument;
    frameDoc.document.open();
    frameDoc.document.write('<html><head>'); // add some libraries for the new document
    frameDoc.document.write('</head><body>');
    frameDoc.document.write(contents);
    frameDoc.document.write('</body></html>');
    frameDoc.document.close();
    setTimeout(function () {
        window.frames["frame3"].focus();
        window.frames["frame3"].print();
        document.body.removeChild(frame1);
    }, 500);

    return false;
};

HTML -

<div id="print-section">
   <div>Section to print<>
</div>

3 个答案:

答案 0 :(得分:2)

经过一番调查后,我找到了解决方案。

Safari仅在您“取消”打印时显示打印警告。 但是,第二次空白打印的原因是您使用

删除了太快的内容
document.body.removeChild(frame1)

如果您将等待时间从500毫秒增加到5秒,则可以让用户有时间关闭警告弹出并打印。

在我的情况下,我在Chrome / FF / Edge / Safari上成功测试了这个jQuery插件,在此库中还增加了删除超时https://github.com/DoersGuild/jQuery.print

答案 1 :(得分:1)

除此之外,使用上面提到的 jQuery Print 插件 Matteo Conta,我能够通过在新标签页中进行打印来在 Safari 中实现打印,没有 iframe、弹出对话框、空白打印或延迟。< /p>

我遇到的问题,就像很多人一样,是 Safari 在 iframe 中的后续打印出现问题,显示打印对话框,然后是空白打印。

目前我们使用 printThis JS 作为我们的打印插件并且已经实现了 3000 毫秒的延迟,但是这个新的更新 Big Sur 14.1 专门破坏了这个实现。 jQuery Print 插件不需要任何延迟,如果我们不再遇到 Safari 更新的问题,我们可能会弃用 printThis。

注意:即使使用 jQuery Print,如果您仍然选择在 iframe 内打印,您也会遇到相同的打印问题。

下面是我如何根据用户的浏览器实现打印的片段。希望这可以帮助任何仍在寻找解决方案的人!

var currentBrowser;

// Determine user browser
if ( navigator.userAgent.indexOf("Chrome") != -1 ) {

  currentBrowser = "Google Chrome";

} else if ( navigator.userAgent.indexOf("Safari") != -1 ) {

  currentBrowser = "Safari";

} else {

  currentBrowser = "Others";
}

// Special Safari Treatment - Print New Window
if( currentBrowser === "Safari" ) {

  /**
   * jQuery Print JS
   *
   * Print receipts in new window with a deffered callback function.
   *
   * globalStyles - Will include style sheets from parent document
   * iframe - Print in a new window, iframe = false
   * deferred - Callback function 
   */
  $("#printDiv").print({
    globalStyles : true,
    iframe : false,
    deferred: $.Deferred().done(function() {

        // Callback
    })
  });

} else {

    // Print iframe normally using printThis JS
    $('#printDiv').printThis();
}

答案 2 :(得分:0)

正如Matteo Conta正确提到的那样,问题在于Safari的打印确认对话框不会停止JS代码执行流以等待打印。
因此,我们真正想要的是检测打印操作何时确切结束,以便绝对安全地进行清理。

setTimeout解决方案是一个很好的起点,但是我想更可靠地解决该问题,并提出了一个基于事件的解决方案,该解决方案使用matchMediaonfocus来捕捉确切的时刻打印完成时(取消或完成)。

下面是我针对此特定问题(ES5,iframe打印)测试过的代码。
另外,我已经用演示的通用方法创建了a Gist on GitHub。希望它会有用。

$scope.print = function () {
  var frame = appendFrame();

  // Safari
  if (!window.onafterprint) {
    // emulate onbeforeprint/onafterprint events
    var mediaQueryCallback = function (mql) {
      if (!mql.matches && frame) {
        document.body.removeChild(frame);
      }
    };
    var mediaQueryList = window.frames[frame.name].matchMedia('print');
    mediaQueryList.addListener(mediaQueryCallback);

    // the code below will trigger a cleanup in case a user hits Cancel button
    // in that Safari's new additional print confirmation dialog
    window.frames[frame.name].focus();
    window.frames[frame.name].onfocus = function () {
      return mediaQueryCallback(mediaQueryList);
    };
  }

  window.frames[frame.name].print();

  return false;
};

为简洁起见,我已将框架创建代码提取到一个简单的函数(appendFrame)中,并从原始问题中省略了setTimeout调用(在frameDoc.document.close();行之后)。

var appendFrame = function () {
  var contents = document.getElementById("print-section").outerHTML;
  var frame1 = document.createElement('iframe');
  frame1.name = "frame3";
  frame1.style.position = "absolute";
  frame1.style.top = "-1000000px";
  document.body.appendChild(frame1);

  var frameDoc = frame1.contentWindow ? frame1.contentWindow : frame1.contentDocument.document ? frame1.contentDocument.document : frame1.contentDocument;
  frameDoc.document.open();
  frameDoc.document.write('<html><head>'); // add some libraries for the new document
  frameDoc.document.write('</head><body>');
  frameDoc.document.write(contents);
  frameDoc.document.write('</body></html>');
  frameDoc.document.close();

  return frame1;
};

受MDN文章启发:

onbeforeprint