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

2024-04-02

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

'此网页正在尝试打印。您想打印该网页吗?

如果我点击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>

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

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

下面是我针对这个特定问题测试过的代码(ES5,iframe 打印)。
另外,我还创建了GitHub 上的要点 https://gist.github.com/capturetheflag/a588f4d5919efebf2eae315aeb9e2297并展示了通用方法。希望它会有用。

$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(); line).

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 https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeprint

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

safari 不允许第二个 window.print() 的相关文章