如何检测window.print()完成


73

在我的应用程序中,我尝试为用户打印出凭证页面,如下所示:

  var htm ="<div>Voucher Details</div>";
  $('#divprint').html(htm);
  window.setTimeout('window.print()',2000);

divprint”是div我的页面中的,用于存储有关凭证的信息。

它可以工作,并弹出打印页面。但是,一旦用户在浏览器的弹出式打印对话框中单击“ print”或“ close”,我就希望推进该应用程序。

例如,我想在关闭弹出窗口后将用户重定向到另一个页面:

window.application.directtoantherpage();//a function which direct user to other page

如何确定关闭弹出式打印窗口或完成打印的时间?

Answers:


118

您可以收听印后事件。

https://developer.mozilla.org/zh-CN/docs/Web/API/window.onafterprint

window.onafterprint = function(){
   console.log("Printing completed...");
}

可能可以使用window.matchMedia以另一种方式获得此功能。

(function() {

    var beforePrint = function() {
        console.log('Functionality to run before printing.');
    };

    var afterPrint = function() {
        console.log('Functionality to run after printing');
    };

    if (window.matchMedia) {
        var mediaQueryList = window.matchMedia('print');
        mediaQueryList.addListener(function(mql) {
            if (mql.matches) {
                beforePrint();
            } else {
                afterPrint();
            }
        });
    }

    window.onbeforeprint = beforePrint;
    window.onafterprint = afterPrint;

}());

资料来源:http//tjvantoll.com/2012/06/15/detecting-print-requests-with-javascript/


3
请记住,媒体查询监听器将afterPrint()立即触发。它不等到打印对话框关闭后,这就是为什么mouseover在使用媒体查询解决方案时我的答案会在听的原因……
quietmint 2013年

2
IE 7不会(无法等待它消失)。onafterprint在打印对话框打开后立即启动。至少那是我的经验。
MPelletier 2014年

10
在IE 11上,在进行打印对话之前(显然,没有打印)
onafterprint就被触发了-wintersylf 2015年

2
在IE 11上存在matchMedia但听众永不
解雇

1
无论用户是否确认打印,都会调用onafterprint。我们如何判断用户是否确认了打印?
伊恩·柯克帕特里克

56

在镀铬(V.35.0.1916.153 m)上尝试以下操作:

function loadPrint() {
    window.print();
    setTimeout(function () { window.close(); }, 100);
}

对我来说很棒。用户完成打印对话框后,它将关闭窗口。


1
我认为这是最简单的解决方案。我喜欢!
daVe

感谢您的回答,我找到了一个简单的解决方案:在打印之前,我已经添加了一个新的答案“ window.open('','_self','');”
AlbertCatalà15

10
可接受的答案仅在极少数浏览器上起作用。在打印后直接放置window.close会导致窗口在打印对话框之前消失。但是,使用setTimeout会导致关闭事件在事件队列中排队,100ms超时实际上不是计时内容,计时器将一直阻塞,直到关闭打印对话框后才启动100ms计时器。更好的解决方案。
路加福音

2
优秀的!适用于Firefox 51.0.1和Chrome 54.0.2840.90
秋季伦纳德(Leonard)

3
在Android上的Chrome v68之后,此功能不再起作用。您需要将超时时间延长到500毫秒,以显示打印对话框,然后,如果您更换打印机,则该窗口已经关闭,浏览器将无法刷新。
Dyluck

11

与chrome,firefox,opera,Internet Explorer兼容
注意:需要jQuery。

<script>

    window.onafterprint = function(e){
        $(window).off('mousemove', window.onafterprint);
        console.log('Print Dialog Closed..');
    };

    window.print();

    setTimeout(function(){
        $(window).one('mousemove', window.onafterprint);
    }, 1);

</script>

3
此处有轻微的错字,$(window).one()应该是$(window).on()。无论如何,很好的解决方案!
杰伊·达达尼亚

2
@JayDadhania这不是错字
Mark Amery

4

https://stackoverflow.com/a/15662720/687315。作为一种解决方法,您可以afterPrintwindow.mediaMatchAPI指示介质不存在后,在窗口(Firefox和IE)上侦听事件,并在文档上侦听鼠标移动(指示用户已关闭打印对话框并返回到页面)。不再与“打印”匹配(Firefox和Chrome)。

请记住,用户可能已经或可能没有实际打印过文档。另外,如果您window.print()在Chrome中通话太频繁,甚至可能不会提示用户进行打印。


4

window.print在chrome上的行为是同步的。在控制台中尝试

window.print();
console.log("printed");

除非用户关闭(取消/保存/打印)打印对话框,否则不会显示“已打印”。

这是有关此问题的更详细说明。

我不确定IE或Firefox稍后是否会检查和更新


4
是的,这是Chrome中的错误,并且已修复。在最新版的chrome中,此功能无效。感谢您的评论,我必须修复产品:)
Rahil Ahmad

1
这仍然有效,至少在chrome(77.0.3865.90)和firefox(69.0.1)上我不了解Edge或Safari
ダミアンರ_ರ

3

您只需将window.print()放入另一个函数中,就可以检测出它何时完成

//function to call if you want to print
var onPrintFinished=function(printed){console.log("do something...");}

//print command
onPrintFinished(window.print());

在Firefox,Google chrome,IE中测试


5
您要做的只是将window.print()的返回值传递给另一个函数,当您调用onPrintFinished时,当然window.print()将首先执行,但前提是浏览器提供了同步的print()方法(最新的例如,Linux上的firefox提供了此功能)onPrintFinished函数将在关闭打印对话框后执行,​​在其他浏览器(例如最新的Chromium)上,print()方法是异步的,因此这是无用的。
emerino 2014年

现代的Chrome,Safari,FireFox ...都支持以这种方式进行操作。
FactoryAidan '18

适用于最新版本的chrome
Josh,

我认为这不是解决此问题的绝佳方法,请在onafterprint上添加事件侦听以关闭窗口。window.onafterprint = function(){ window.close()};
拉哈特·哈米德

2

这实际上对我来说适合Chrome。我很惊讶。

jQuery(document).bind("keyup keydown", function(e){
    if(e.ctrlKey && e.keyCode == 80){
         Print(); e.preventDefault();
    }
});

我写的其中Print是一个调用window.print();的函数。如果禁用Print(),它也可以用作纯阻止程序。

如用户3017502此处所述

window.print()将暂停,因此您可以像这样添加onPrintFinish或onPrintBegin

function Print(){
    onPrintBegin
    window.print();
    onPrintFinish(); 
}

2

考虑到您希望等待打印对话框消失,我将在窗口上使用焦点绑定。

print();

var handler = function(){
    //unbind task();
    $(window).unbind("focus",handler);
}

$(window).bind("focus",handler);

通过在处理程序函数中加入取消绑定,我们可以防止焦点事件保持与窗口的绑定。


您好像忘了关闭"focus:)
TobiasR。

1

使用w = window.open(url,'_blank')在新窗口中打印,然后尝试w.focus(); w.close(); 并检测页面何时关闭。在所有浏览器中均可使用。

w = window.open(url, '_blank');
w.onunload = function(){
 console.log('closed!');
}
w.focus();
w.print();
w.close();

完成打印后窗口关闭。


在IE 11上这对我有效,但这只是第一次。随后每当我打开窗口时,它都会自动关闭,而无需进行打印对话
wintersylf 2015年

是Internet Explorer的错误。向Microsoft报告并等待他们获得补丁或使用其他替代方法。
e-info128 '17

不仅仅是Internet Explorer会失败。在Chrome中,这通常会打印空白页面,因为它是w.print()异步发生的,并且w.close()在实际准备好打印页面之前,已将页面从其脚下拉出。
Mark Amery

1

经过IE,FF,Chrome的测试,可以正常运行。

    setTimeout(function () { window.print(); }, 500);
    window.onfocus = function () { setTimeout(function () { window.close(); }, 500); }

这里缺少一些细节,但是尽我所能将其填充,对于我来说仍然不起作用(在Ubuntu 19.10上的Chrome 80中)。如果要打印已经集中的页面,则该页面在任何时候都不会失去焦点,因此onfocus完成后不会触发。如果您正在打印iframe,则您所在的页面会失去焦点,但是打印完成后不会自动重新获得它,因此仍然无法正常工作。
Mark Amery

1

它对我有用$(window).focus()。

var w;
var src = 'http://pagetoprint';
if (/chrom(e|ium)/.test(navigator.userAgent.toLowerCase())) {
    w = $('<iframe></iframe>');
    w.attr('src', src);
    w.css('display', 'none');
    $('body').append(w);
    w.load(function() {
        w[0].focus();
        w[0].contentWindow.print();
    });
    $(window).focus(function() {
        console.log('After print');
    });
}
else {
    w = window.open(src);
    $(w).unload(function() {
        console.log('After print');
    });
}

0

我认为窗口聚焦方法是正确的。这是一个示例,我想在一个隐藏的iframe中打开PDF网址blob并进行打印。打印或取消后,我想删除iframe。

/**
 * printBlob will create if not exists an iframe to load
 * the pdf. Once the window is loaded, the PDF is printed.
 * It then creates a one-time event to remove the iframe from
 * the window.
 * @param {string} src Blob or any printable url.
 */
export const printBlob = (src) => {
  if (typeof window === 'undefined') {
    throw new Error('You cannot print url without defined window.');
  }
  const iframeId = 'pdf-print-iframe';
  let iframe = document.getElementById(iframeId);
  if (!iframe) {
    iframe = document.createElement('iframe');
    iframe.setAttribute('id', iframeId);
    iframe.setAttribute('style', 'position:absolute;left:-9999px');
    document.body.append(iframe);
  }
  iframe.setAttribute('src', src);
  iframe.addEventListener('load', () => {
    iframe.contentWindow.focus();
    iframe.contentWindow.print();
    const infanticide = () => {
      iframe.parentElement.removeChild(iframe);
      window.removeEventListener('focus', infanticide);
    }
    window.addEventListener('focus', infanticide);
  });
};

1
我有一个问题exports is not defined
aldoblack

这不能直接解决所问的问题。在两行之间阅读,我想infanticide如果我们希望它在打印后运行,我们可以向该函数添加代码。但这也不是很正确。至少在我的浏览器(Ubuntu 19.10上的Chrome 80)上,该窗口在打印后不会立即重新获得焦点-仅当我单击或跳回到该窗口时。
Mark Amery

0

由于打印后浏览器的行为不同,这很困难。桌面版Chrome浏览器内部处理打印对话框,因此不会在打印后转移焦点,但是,afterprint事件在这里工作正常(截至目前为81.0)。另一方面,在移动设备和大多数其他浏览器上的Chrome浏览器在打印和afterprint事件在此无法正常运行。鼠标移动事件在移动设备上不起作用。

因此,检测是否为Desktop Chrome,如果,请使用afterprint事件。如果,请使用基于焦点的检测。您还可以结合使用鼠标移动事件(仅适用于台式机),以涵盖更多浏览器和更多方案。


0

您真的不知道用户是否单击了按钮printof,cancel因为他们都触发了同一事件,onafterprint或者afterprint 我认为这非常愚蠢,为什么不区分这两个事件?


-1

实现window.onbeforeprint和window.onafterprint

在Chrome v 78.0.3904.70中window.print()之后无法使用window.close()调用

为了解决这个问题,我使用亚当的答案进行了简单的修改:

     function print() {
    (function () {
       let afterPrintCounter = !!window.chrome ? 0 : 1;
       let beforePrintCounter = !!window.chrome ? 0 : 1;
       var beforePrint = function () {
          beforePrintCounter++;
          if (beforePrintCounter === 2) {
             console.log('Functionality to run before printing.');
          }
       };
       var afterPrint = function () {
          afterPrintCounter++;
          if (afterPrintCounter === 2) {
             console.log('Functionality to run after printing.');
             //window.close();
          }
       };
       if (window.matchMedia) {
          var mediaQueryList = window.matchMedia('print');
          mediaQueryList.addListener(function (mql) {
             if (mql.matches) {
                beforePrint();
             } else {
                afterPrint();
             }
          });
       }
       window.onbeforeprint = beforePrint;
       window.onafterprint = afterPrint;
    }());
    //window.print(); //To print the page when it is loaded
 }

我在这里称呼它:

<body onload="print();">

这对我有用。请注意,我对这两个功能都使用了计数器,以便可以在不同的浏览器中处理此事件(在Chrome中触发两次,在Mozilla中触发一次)。要检测浏览器,您可以参考此答案


最好检查一下onafterprint,如果存在则使用它,否则尝试matchMedia破解。用您的方式,您永远不会在旧版本的Chrome中调用处理程序(如果可以相信亚当的答案),matchMedia但是这种方法onafterprint无效,并且您将在除Chrome之外的任何浏览器中两次调用它工作。
Mark Amery
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.