在AngularJS单页应用中使用JavaScript打印一个div

34

我有一个使用AngularJS的单页Web应用程序。我需要打印某个页面的div。 我尝试了以下方法:

该页面包含几个div(print.html)

<div>
  <div>
    Do not print
  </div>
  <div id="printable">
    Print this div
  </div>
  <button ng-click="printDiv('printableArea');">Print Div</button>
</div>

该控制器拥有以下脚本:

$scope.printDiv = function(divName) {
    var printContents = document.getElementById(divName).innerHTML;
    var originalContents = document.body.innerHTML;        
    document.body.innerHTML = printContents;
    window.print();
    document.body.innerHTML = originalContents;
}
这段代码可以打印出所需的 div,但存在一个问题。语句 document.body.innerHTML = originalContents; 替换了整个应用程序的 body,因为它是单页应用(SPA)。因此当我刷新页面或再次点击打印按钮时,整个页面的内容都会被清除。

请包含一个 Fiddle。 - Quinn
7个回答

90
$scope.printDiv = function(divName) {
  var printContents = document.getElementById(divName).innerHTML;
  var popupWin = window.open('', '_blank', 'width=300,height=300');
  popupWin.document.open();
  popupWin.document.write('<html><head><link rel="stylesheet" type="text/css" href="style.css" /></head><body onload="window.print()">' + printContents + '</body></html>');
  popupWin.document.close();
} 

同样的问题,所有的$http请求都会中断,但只有在关闭新窗口时才会发生这种情况。Firefox或IE工作正常。 - Eduardo Chavira
1
我找到了为什么这个解决方案不起作用,答案在这里 - https://dev59.com/LGAg5IYBdhLWcg3w3uQR - Eduardo Chavira
有没有像这样的函数,可以将特定的div转换并下载为PDF文件? - gsk
这对我来说非常有效,但在我点击“打印”或“取消”后,它会留下一个包含文档的窗口。是否可能在打印或取消后关闭该窗口? - John Mark
以上解决方案有效,但是像字体颜色和div背景颜色这样的样式在打印时没有被呈现出来!有什么建议吗? - HARDIK THAKOR
显示剩余3条评论

11

需要两个条件函数:一个用于谷歌浏览器,另一个用于其他浏览器。

$scope.printDiv = function (divName) {

    var printContents = document.getElementById(divName).innerHTML; 

    if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
        var popupWin = window.open('', '_blank', 'width=600,height=600,scrollbars=no,menubar=no,toolbar=no,location=no,status=no,titlebar=no');
        popupWin.window.focus();
        popupWin.document.write('<!DOCTYPE html><html><head>' +
            '<link rel="stylesheet" type="text/css" href="style.css" />' +
            '</head><body onload="window.print()"><div class="reward-body">' + printContents + '</div></body></html>');
        popupWin.onbeforeunload = function (event) {
            popupWin.close();
            return '.\n';
        };
        popupWin.onabort = function (event) {
            popupWin.document.close();
            popupWin.close();
        }
    } else {
        var popupWin = window.open('', '_blank', 'width=800,height=600');
        popupWin.document.open();
        popupWin.document.write('<html><head><link rel="stylesheet" type="text/css" href="style.css" /></head><body onload="window.print()">' + printContents + '</body></html>');
        popupWin.document.close();
    }
    popupWin.document.close();

    return true;
}

1
为什么你要使用 onbeforeunloadoriginalContents?另外,你在 popupWin.document.write 行中缺少 </body> 标签。 - Trisped
非常好,谢谢。只是一个未使用的变量:originalContents - Rudi Strydom

7

1
这个库还在不断变化中,我建议在一些问题得到解决之前谨慎在生产环境中使用它。 - G.Mart
@G.Mart 显然,作者本周末将推出一个重大更新,解决跨浏览器兼容性问题。 - TMichel
2
作者三天前说:“是的,非常抱歉多浏览器兼容性更新不及时。我预计本周末发布一个新版本,支持Chrome、Mozilla和Safari。Edge将得到大部分支持,但仍可能存在一两个错误。” - G.Mart
很遗憾,没有IE的参考,而Edge则会是一个未知因素。 - G.Mart

1
我这样做了:

我这样做了:

$scope.printDiv = function (div) {
  var docHead = document.head.outerHTML;
  var printContents = document.getElementById(div).outerHTML;
  var winAttr = "location=yes, statusbar=no, menubar=no, titlebar=no, toolbar=no,dependent=no, width=865, height=600, resizable=yes, screenX=200, screenY=200, personalbar=no, scrollbars=yes";

  var newWin = window.open("", "_blank", winAttr);
  var writeDoc = newWin.document;
  writeDoc.open();
  writeDoc.write('<!doctype html><html>' + docHead + '<body onLoad="window.print()">' + printContents + '</body></html>');
  writeDoc.close();
  newWin.focus();
}

0

好的,我可能有一些甚至不同的方法。

我知道它不适合每个人,但仍然有人可能会发现它有用。

对于那些不想弹出新窗口,并且像我一样关心 CSS 样式的人,这就是我想出来的方法:

我将应用程序的视图包装在另一个容器中,在打印时隐藏该容器,并为需要打印的内容提供了另一个容器,该容器在打印时显示。

以下是一个可行的示例:

var app = angular.module('myApp', []);
 app.controller('myCtrl', function($scope) {
  
    $scope.people = [{
      "id" : "000",
      "name" : "alfred"
    },
    {
      "id" : "020",
      "name" : "robert"
    },
    {
      "id" : "200",
      "name" : "me"
    }];

    $scope.isPrinting = false;
  $scope.printElement = {};
  
  $scope.printDiv = function(e)
  {
   console.log(e);
   $scope.printElement = e;
   
   $scope.isPrinting = true;
      
      //does not seem to work without toimeouts
   setTimeout(function(){
    window.print();
   },50);
   
   setTimeout(function(){
    $scope.isPrinting = false;
   },50);
   
   
  };
    
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="myApp" ng-controller="myCtrl">

 <div ng-show="isPrinting">
  <p>Print me id: {{printElement.id}}</p>
    <p>Print me name: {{printElement.name}}</p>
 </div>
 
 <div ng-hide="isPrinting">
    <!-- your actual application code -->
    <div ng-repeat="person in people">
      <div ng-click="printDiv(person)">Print {{person.name}}</div>
    </div>
  </div>
  
  
</div>
 

请注意,我知道这不是一个优雅的解决方案,并且它有一些缺点,但它也有一些好处:
  • 不需要弹出窗口
  • 保持 CSS 不变
  • 不会将整个页面存储到变量中(如果您不想这样做的话)
无论您是谁在阅读这篇文章,祝您有一个愉快的一天,并继续编码 :)
编辑:
如果适合您的情况,您实际上可以使用:
@media print  { .noprint  { display: none; } }
@media screen { .noscreen { visibility: hidden; position: absolute; } }

使用Angular布尔值选择打印和非打印内容的替代方法

编辑:

更改屏幕CSS,因为显示:none会在页面加载/刷新后第一次打印时破坏打印。

目前似乎使用visibility:hidden方法可以解决问题。


0

这是在Chrome和Firefox中对我有效的方法!这将打开一个小的打印窗口,并在您点击打印后自动关闭。

var printContents = document.getElementById('div-id-selector').innerHTML;
            var popupWin = window.open('', '_blank', 'width=800,height=800,scrollbars=no,menubar=no,toolbar=no,location=no,status=no,titlebar=no,top=50');
            popupWin.window.focus();
            popupWin.document.open();
            popupWin.document.write('<!DOCTYPE html><html><head><title>TITLE OF THE PRINT OUT</title>' 
                                    +'<link rel="stylesheet" type="text/css" href="app/directory/file.css" />' 
                                    +'</head><body onload="window.print(); window.close();"><div>' 
                                    + printContents + '</div></html>');
            popupWin.document.close();

-3

我认为没有必要写这么多的代码。

我刚刚安装了angular-print bower包,一切都准备就绪。

只需将其注入模块,您就可以开始使用了 使用预构建的打印指令,有趣的是您还可以隐藏某些div(如果您不想打印)

http://angular-js.in/angularprint/

我的运行得非常好。


这并没有回答问题。一旦您拥有足够的声望,您将能够评论任何帖子;相反,提供那些不需要询问者澄清的答案 - GrumpyCrouton
谢谢你的建议,但我认为答案更准确。而且它百分之百有效。 - Palak Dhingra
这里已经有一个基本上与您相同的答案,因此您的答案没有为此主题添加任何新内容。我甚至会说那个答案也是无效的,因为它只是一个指向外部来源的链接,可能与主题无关,如果该链接失效,您的答案和他们的答案都将失效,因为您的答案就是链接。 - GrumpyCrouton
这非常愚蠢。 - user1099258

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