有没有一种 Angular 的方法可以打印 HTML 页面中的 div 元素?

10

我有一个使用AngularJS的HTML页面,我想从中打印出一个div。是否有一种Angular方法可以实现呢?还是只能使用下面经典的JavaScript方式:

    <script language="javascript" type="text/javascript">
    function printDiv(divID) {
        //Get the HTML of div
        var divElements = document.getElementById(divID).innerHTML;
        //Get the HTML of whole page
        var oldPage = document.body.innerHTML;

        //Reset the page's HTML with div's HTML only
        document.body.innerHTML =
        "<html><head><title></title></head><body>" +
        divElements + "</body>";

        //Print Page
        window.print();

        //Restore orignal HTML
        document.body.innerHTML = oldPage;
        }
    </script> 
如果在AngularJS中没有类似的功能,您能否推荐一种方式来实现它,而不使用JavaScript函数(例如:doc.getElementById()),接近于AngularJS方式的方法? 谢谢。

创建一个打印指令,同时使用angular.element - tymeJV
你上面的代码不会导致所有事件/ JavaScript 数据在该 HTML 上丢失吗?您可以通过使用 iframe 或以同样的方式打开新窗口来实现基本相同的功能,而不会丢失该信息。 - Kevin B
最终,我使用ng-hide指令(用于隐藏所有不想打印的元素),并在控制器中的一个函数中简单地调用windows.print()完成了它。在我看来,这是目前为止最好的解决方案。 - Ionut Ursan
如果您想隐藏元素并防止其打印,则可以使用媒体查询打印并在其中隐藏元素,如下所示:@media print { body * { visibility:hidden; } .class-to-print { visibility: visible; } } - Arne H. Bitubekk
3个回答

16

我使用 iframe 技术创建了一个简单的指令来打印 div 内容。虽然有点 hackish,但非常有效。在我的观点中,没有更好的方法来做这件事。指令脚本如下:

'use strict';

angular.module('yourAppNameHere').directive('printDiv', function () {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      element.bind('click', function(evt){    
        evt.preventDefault();    
        PrintElem(attrs.printDiv);
      });

      function PrintElem(elem)
      {
        PrintWithIframe($(elem).html());
      }

      function PrintWithIframe(data) 
      {
        if ($('iframe#printf').size() == 0) {
          $('html').append('<iframe id="printf" name="printf"></iframe>');  // an iFrame is added to the html content, then your div's contents are added to it and the iFrame's content is printed

          var mywindow = window.frames["printf"];
          mywindow.document.write('<html><head><title></title><style>@page {margin: 25mm 0mm 25mm 5mm}</style>'  // Your styles here, I needed the margins set up like this
                          + '</head><body><div>'
                          + data
                          + '</div></body></html>');

          $(mywindow.document).ready(function(){
            mywindow.print();
            setTimeout(function(){
              $('iframe#printf').remove();
            },
            2000);  // The iFrame is removed 2 seconds after print() is executed, which is enough for me, but you can play around with the value
          });
        }

        return true;
      }
    }
  };
});

在您的模板中,您可以像这样标记打印按钮:

<a href="#" print-div=".css-selector-of-the-div-you-want-to-print">Print!</a>

就这样,它应该能够起作用了。 把iFrame移除的过程有点"hackish",因为没有跨浏览器的方法来检测打印执行的结束,所以你需要估计需要多少时间才能运行完。

你可能需要包含jQuery才能让它工作,我不确定,因为我几乎从不没有使用它。我添加了一些内联注释,使事情更清晰。我使用了 这个答案 中的一些代码来打印div内容(但是在Angular.js之外)。也许你会更喜欢那种方法。


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Wanny Miarelli
这是一个干净的解决方案,不需要 jQuery 插件!谢谢,非常有用。 - Michelangelo
@MladenDanic 虽然我非常喜欢这个解决方案,但似乎无法加载外部 CSS 样式表。我被迫使用 HTML 样式标签。有没有解决这个问题的方法?我有很多样式要做 :)...它很快就变得混乱了。 - Michelangelo
@Mikey,你是否在iFrame中加载了样式表?(在代码中写着“// Your styles here, I needed the margins set up like this”) - Mladen Danic
@MladenDanic 另外,我遇到的另一个问题是它在 IE11 中无法工作。我尝试打开一个 iframe 但失败了...因此下面的回答也是正确的。 - Michelangelo
显示剩余2条评论

5

我需要这个在IE8+中可用。

'use strict';

angular
.module('print-div', [])
.directive('printDiv', function () {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {

            var iframe;
            var elementToPrint = document.querySelector(attrs.printDiv);

            if (!window.frames["print-frame"]) {
                var elm = document.createElement('iframe');
                elm.setAttribute('id', 'print-frame');
                elm.setAttribute('name', 'print-frame');
                elm.setAttribute('style', 'display: none;');
                document.body.appendChild(elm);
            }

            function write(value) {
                var doc;
                if (iframe.contentDocument) { // DOM
                    doc = iframe.contentDocument;
                } else if (iframe.contentWindow) { // IE win
                    doc = iframe.contentWindow.document;
                } else {
                    alert('Wonder what browser this is... ' + navigator.userAgent);
                }
                doc.write(value);
                doc.close();
            }

            element.bind('click', function(event) {
                iframe = document.getElementById('print-frame');
                write(elementToPrint.innerHTML);

                if (window.navigator.userAgent.indexOf ("MSIE") > 0) {
                    iframe.contentWindow.document.execCommand('print', false, null);
                } else {
                    iframe.contentWindow.focus();
                    iframe.contentWindow.print();
                }
            });
        }
    };
});

我简直不敢相信。IE总是让人头疼。第一个答案似乎有效,但在IE中测试后却出现问题。这个程序在其他浏览器中也能正常工作吗? - Michelangelo

-1

angularPrint是一个非常易于使用的Angular指令。 https://github.com/samwiseduzer/angularPrint

您只需使用其自定义属性装饰您的HTML即可:

<div>
  <div print-section>
    I'll print
    <p>Me, too!</p>
  </div>
  <div>I won't</div>
</div>

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