打印功能仅在第二次单击后有效

时间:2017-02-06 13:08:36

标签: javascript

我有这个功能来打印DIV 每当页面加载并点击我的“打印”链接时,显示DIV没有CSS打印。
如果我关闭Chrome的打印可视化页面并再次单击“打印”链接,则DIV已应用CSS。

任何想法为什么?

的Javascript

function printDiv(divId) {

  var printDivCSSpre =
'<link href="/static/assets/vendor/sb-admin-2-1.0.7/bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">' +
'<link href="/static/assets/vendor/sb-admin-2-1.0.7/dist/css/sb-admin-2.css" rel="stylesheet">' +
'<div style="width:1000px; padding-right:20px;">';

  var printDivCSSpost = '</div>';

  $('body').append('<iframe id="print_frame" name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>');

    $("link").clone().appendTo($("#print_frame").contents().find("head"));
window.frames["print_frame"].document.body.innerHTML =
    printDivCSSpre + document.getElementById(divId).innerHTML + printDivCSSpost;
  window.frames["print_frame"].window.focus();
  var windowInstance = window.frames["print_frame"].window;
  windowInstance.print();
}

HTML

<a id="print" href="#">
    <i class="fa fa-print"></i> Print
</a>
<script>
    $('#print').click(function () {
        printDiv('report')
    })
</script>

<div id="report" class="report">
    <p># Generated Table#</p>
</div>

首先点击:

http://imgur.com/a/Go81Y

关闭打印预览页面并再次单击打印

http://imgur.com/a/SCxJF

6 个答案:

答案 0 :(得分:3)

这是因为当您调用printDiv()函数时,css也是使用内部HTML编写的,在这种情况下,在第一次单击时不会应用CSS,因为即使在DIV中不存在CSS,也会向元素编写CSS。 / p>

根据需要工作的功能必须先写入DIV内容,然后再应用CSS。我会说在DIV的内容之后写css或者在HTML页面上加载,然后只写DIV内容。

希望有所帮助。

答案 1 :(得分:2)

正如其他人提到的,如果没有看到问题的工作示例很难看到你的问题,而只是从代码中猜测:

  1. 浏览器无法在print()来电之前加载CSS。
  2. 浏览器无法在print()来电之前呈现CSS。
  3. 记住改变你的JS功能可能会有所作为

    function printDiv(divId) {
        $("link").clone().appendTo($("#print_frame").contents().find("head"));
        window.frames["print_frame"].document.body.innerHTML =
            printDivCSSpre + document.getElementById(divId).innerHTML + printDivCSSpost;
        window.frames["print_frame"].window.focus();
        var windowInstance = window.frames["print_frame"].window;
        setTimeout(function() {
            windowInstance.print();
        }, 0);
    }
    

    这个功能背后的想法是让浏览器在我们在窗口中添加更改HTML / CSS代码后执行它的代码 - 请参阅Why is setTimeout(fn, 0) sometimes useful?

    警告:此方法未针对您的特定问题进行测试,也可能无效,因为我们转义/离开鼠标单击调用堆栈,调用print()方法可能是不可能超出用户交互堆栈。

    查看发布的jsfiddle后,

    更新: - 我的假设是正确的,浏览器需要一些时间来加载和渲染CSS,这就是为什么在更改iframe后调用print()的权利内容没有给出所需的结果。有3.5种方法可以解决这个问题:

    1. 使用事件来识别iframe文档和窗口何时完成加载和渲染。我尝试了两种方法,到目前为止都失败了,需要更仔细地阅读文档,了解文档和窗口在加载过程中的时间:
      • 我们可以从iframe外部执行此操作,即收听iframe元素及其子项的事件
      • 我们可以从iframe内部执行此操作,即添加一些小的javascript代码段,在完成加载后会向父窗口发送消息。
    2. 考虑将打印结果形成不同,打印样式表怎么样?即添加一个带有打印媒体查询的样式表到父文档,并在其上调用print?
    3. 考虑形成一个已加载并准备打印的iframe,但只替换其中的表格内容。

答案 2 :(得分:2)

试试这个。问题主要是因为在启动打印命令时css尚未应用于页面。 setTimeout是其他人提到的解决问题的一种方法,但实际上无法预测您需要多少延迟。在触发print语句之前,缓慢的Internet连接需要很长的延迟。但是,以下代码仅在将css正确应用于iframe后触发打印事件。

$('#print').click(function () {

    if($("#print_frame").length == 0) {
        $('#report').after('<iframe id="print_frame" name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>');
    }

    var $head = $("#print_frame").contents().find("head");

        // for now for ease I will just empty head
        // ideally you would want to check if this is not empty
        // append css only if empty
        $head.empty();
        $.ajax({
            url : "https://dl.dropboxusercontent.com/u/7760475/reports.css",
            dataType: "text",
            success : function (reports) {
                // grab css and apply its content to the iframe document
                $head.append('<style>'+reports+'</style>');
                $.ajax({
                    url : "https://dl.dropboxusercontent.com/u/7760475/bootstrap.css",
                    dataType: "text",
                    success : function (bootstrap) {
                        // grab another css and apply its content to the iframe document
                        // there may be better ways to load both css files at once but this works fine too
                        $head.append('<style>'+bootstrap+'</style>');
                        // css has been applied
                        // clone your div and print
                        var $body = $("#print_frame").contents().find('body');
                            // empty for ease
                            // but later append content only if empty
                            $body.empty();

                        $("#report").clone().appendTo($body);
                        $('#print_frame').get(0).contentWindow.print();
                    }
                });
            }
        });
});

答案 3 :(得分:1)

正如其他人所提到的,这里的问题是使用的CSS文件是外部资源,浏览器需要时间下载并在本地缓存。一旦它被缓存,它将更快地服务,这就是为什么它在第二次点击时工作正常。

正如Anton所说,setTimeout是关键所在!您可能会增加超时秒数以使其工作。我尝试将其设置为500毫秒,这很有效,

setTimeout(function(){windowInstance.print();},500);

答案 4 :(得分:1)

使用内联CSS代替。 原因:如果我们打印或保存为PDF,如果无法获取外部css文件,那么我们必须使用内联css。 编辑了您的文件,请参阅:jsfiddle.net/ytzcwykz/18 /

答案 5 :(得分:1)

每件事都是对的,只需改变顺序。在第一次单击的浏览器调试器中,它在源部分中没有显示'print_frame',而在第二次单击时它(我使用的是chrome devtool)。

因此在onload期间加载内存帧并使用css属性:

BC/OpenSSL

和onClick只需附加html

var windowInstance;
$(function(){
    $('body').append('<iframe id="print_frame" name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>');
    $("link").clone().appendTo($("#print_frame").contents().find("head"));
    windowInstance = window.frames["print_frame"].window;

});

更新jsfiddle