【问题标题】:safari not allowing a second window.print()Safari 不允许第二个 window.print()
【发布时间】:2018-07-09 12:46:28
【问题描述】:

您好,我在 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>

【问题讨论】:

  • 同样的问题,有什么想法吗?

标签: javascript html printing safari


【解决方案1】:

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

仅当您“取消”打印时,Safari 才会显示打印警告。 然而,第二个空白打印的原因是您使用

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

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

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

【讨论】:

  • 您找到其他解决方案了吗?我的意思是 5 秒是很长的时间......
  • @Laura 不,抱歉,这个解决方案有效,我没有检查其他解决方案。 5 秒是您的用户必须关闭警告的时间,您可以调整它,但它与 setTimeout 打印功能异步,因此如果太低,则风险是打印空白页。
【解决方案2】:

正如 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

【讨论】:

    【解决方案3】:

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

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

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

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

    下面是我如何根据用户的浏览器实现打印的 sn-p。希望这对仍在寻找解决方案的人有所帮助!

    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();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-11
      • 2018-03-30
      • 1970-01-01
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      • 2017-10-04
      相关资源
      最近更新 更多