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

pau*_*590 6 html javascript 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;
};
Run Code Online (Sandbox Code Playgroud)

HTML的

<div id="print-section">
   <div>Section to print<>
</div>
Run Code Online (Sandbox Code Playgroud)

Fed*_*dor 5

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

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

下面是我针对这个特定问题测试过的代码(ES5,iframe 打印)。
此外,我还在GitHub 上创建了一个 Gist,并演示了通用方法。希望它会有用。

$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;
};
Run Code Online (Sandbox Code Playgroud)

为了简洁起见,我将框架创建代码提取到一个简单的函数(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;
};
Run Code Online (Sandbox Code Playgroud)

灵感来自 MDN 文章:

onbeforeprint


Mat*_*nta 3

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

仅当您“取消”打印时,Safari 才会显示打印警告。然而,第二次空白打印的原因是您使用太快删除内容

document.body.removeChild(frame1)
Run Code Online (Sandbox Code Playgroud)

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

就我而言,我成功地在 Chrome/FF/Edge/Safari 上测试了这个 jQuery 插件,还在这个库中增加了删除超时https://github.com/DoersGuild/jQuery.print