通过iframe将浏览器中的PDF URL发送到打印机

3
对于现有的非IE浏览器(Chrome、Firefox、Opera、Safari),我希望能够根据PDF的URL将PDF文档发送到打印机。
为了避免出现多余的弹窗,我目前使用<iframe>实现此功能,但我希望在打印完成后关闭iframe,否则某些浏览器会在尝试离开页面时弹出对话框。
以下是我目前想到的解决方案(为了简单起见,使用了lodash和jQuery):
var _print_url, _remove_iframe, _set_print;

_print_url = function(src_url) {
  $("<iframe src='" + src_url + "' type='application/pdf'>").css({
    visibility: 'hidden',
    position: 'fixed',
    right: '0',
    bottom: '0'
  }).on('load', _set_print).appendTo(document.body);
};

_remove_iframe = function(iframe) {
  return $(iframe).parent().find(iframe).detach();
};

_set_print = function() {
  this.contentWindow.print();
/* 
 * Where we could do @contentWindow.close() with a window, we must remove the
 * print iframe from the DOM. We have to engage in some async madness
 * it seems, for no apparent reason other than this won't work
 * synchronously (@cw.print above must be async, it seems) - even though 
 * window.close() appears to work synchronously.
 */
  _.delay(_.partial(_remove_iframe, this), 100);
};

有时候使用Google Chrome打印对话框会正确地显示PDF文件,但当用户选择打印机并确认打印意图后,实际上会将帧的父页面内容发送到打印机而不是PDF本身。
这里有一个链接Mozilla页面上的建议,但该文档目前似乎已经过时了。我能找到的最好的例子是通过反向工程亚马逊Web服务中的发票打印对话框,但那会弹出一个窗口。
我考虑的一个替代方案是Google Cloud Print,但显然这需要安装额外的软件或配置Google账户,除非必要,否则我不愿意强加给用户。
有没有其他例子可以在给定URL的情况下打印PDF,特别是使用Javascript且不使用超量的浏览器附加组件或类似弹出窗口之类的工具?

这只是一个猜测,但如果在调用 print() 之前调用 this.contentWindow.focus() 会发生什么? - Jordan Gray
@YatinSaraiya 这里的“this”指的是iframe。jQuery将“this”绑定到定义事件处理程序的元素上。(请参见此处,该部分的最后一段。) - Jordan Gray
1个回答

3

-- 注意:使用此方法,您将永远不会看到弹出窗口拦截器 --

几个月前,我遇到了一个类似的问题,是在与Ajax应用程序中运行时遇到的。问题是在发送打印请求之前需要创建并存储PDF文件,解决方法如下:

我没有使用iframes。该应用程序使用php的TCPDF创建pdf,采用jqueryunderscore作为模板系统。

您可以在http://www.screenr.com/Ur07观看演示视频(2:18分钟)。

  1. 通过JSON(ajax)发送信息。由于所有内容都在ajax中,所以无法使用post发送信息,因此我将一个隐藏的form附加到DOM中,并使用target="_blank"将其发布到新窗口(该窗口将在过程结束时关闭)。

HTML隐藏虚拟表单

<form method='<%= method %>' 
      action="<%= action %>" 
      name="<%= name %>" 
      id="<%= id %>" 
      target="_blank">
    <input type='hidden' name='json' id='<%= valueId %>' />
</form>

JavaScript(简称JS)

 function makePost(){
  var _t = _.template(_JS_Templates["print.form.hidden"]); //this the html of the form

  var o = {
    method : "POST",
    action : js_WEB_ + "/print.php",
    name : "print_virtual_form",
    id : "print_virtual_form_id",
    valueId : "print_virtual_value"
  }

 var form = _t(o);
 $(".warp").append(form); //appending the form to the dom

  var json = {
    data : data // some data
  }     

 $("#print_virtual_value").val(JSON.stringify(json)); //assing to the hidden input the value and stringify the json
 $("#print_virtual_form_id").submit(); //make the post submmitting the form
 $("#print_virtual_form_id").remove(); //removing the "virtual hidden form"

}

2.- 当你收到JSON数据时(在我的情况下使用的是PHP),你需要创建任何你需要的东西。我是用以下方式实现的,你可以在这个例子中看到PHP代码(这是我的答案)。

使用TCPDF在ajax调用上生成PDF

3.- 最后,在这里有一些很酷的部分,就是响应。在这一部分中,我使用PHP文件编写了一段JavaScript代码,告诉它关闭父窗口并将JSON答案报告给一个特定的函数,这是一种回调。

switch($_SERVER['REQUEST_METHOD']){
    case "GET":
        echo "Denied";
    break;

    case "POST":
        if(isset($_POST["json"])){
            if(!empty($_POST["json"])){
                $json = $_POST["json"];             
                $hash = PDF::makePDF($json);
                echo "<script>
                  function init() {
                        //calling callback
                                        //returning control to the previous browser
                                 window.opener.someclass.finish('".$hash."');
                                 window.close();
                    }
                window.onload = init;                       
             </script>";
            }else{
                echo "not json detected";
            }
        }else{
            echo "not json detected";
        }
    break;

4. 最后,在你的浏览器窗口中,你可以控制它。

var someobject = (function(name){
  //private
  var finish(data){
    //do whatever you want with the json data
  }

   //public
   var $r = {};
   $r.finish = function(data){ 
     finish(data); //you will pass the data to the finish function and that is..!! voila!!
   }

   return $r;
})("someobject");

我知道这不完全是你要求的,但这是解决相同问题的另一种方法。虽然我认为这可能会更加复杂,但我可以保证在许多浏览器中都有效,并且用户将喜欢您的操作方式。他们永远不会看到发生了什么,只需点击链接并保存文件即可下载文件。
这只是我的个人建议,祝编码愉快。

1
非常感谢您对讨论的贡献。这似乎是一个真正的利基问题,所以我很感激任何想法和建议,这看起来很不错。干杯。 - Brian M. Hunt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接