[英]Print function only works after second click
I have this function to print a DIV. 我有这个功能来打印DIV。
Whenever the page is loaded and I click in a "Print" link I have, the DIV is shown to be printed without CSS. 每当页面加载并点击我的“打印”链接时,显示DIV没有CSS打印。
If I close Chrome's print visualization page and click in the "Print" link again, the DIV has CSS applied. 如果我关闭Chrome的打印可视化页面并再次单击“打印”链接,则DIV已应用CSS。
Any ideas why? 有什么想法吗?
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();
}
<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/Go81Y
This happens because when you call your printDiv() function, css is also written using inner HTML and in this scenario CSS is not applied during first click because you wrote CSS to the elements even when they do not exist inside DIV. 发生这种情况是因为当您调用printDiv()函数时,css也是使用内部HTML编写的,在这种情况下,CSS在第一次单击时不会应用,因为即使在DIV中不存在CSS,也会向元素编写CSS。
The function to work as desired has to write DIV contents first and then CSS should be applied. 根据需要工作的函数必须首先编写DIV内容,然后应该应用CSS。 I would say write css after contents of DIV or load on top of your HTML page and just write DIV contents.
我会说在DIV的内容之后写css或者在HTML页面上加载并且只写DIV内容。
Hope that helps. 希望有所帮助。
As other people mentioned it is hard to see your problem without seeing the working example of a problem, but just guessing from the code: 正如其他人提到的,如果没有看到问题的工作示例很难看到你的问题,而只是从代码中猜测:
print()
call. print()
调用之前加载CSS。 print()
call. print()
调用之前呈现CSS。 Keeping that in mind changing your JS function that way might do the trick 记住改变你的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);
}
The idea behind this function is to let browser execute it's code after we added changed the HTML/CSS code in the window - see Why is setTimeout(fn, 0) sometimes useful? 这个函数背后的想法是让我们在窗口中添加更改HTML / CSS代码后让浏览器执行它的代码 - 请参阅为什么setTimeout(fn,0)有时会有用?
WARNING: this approach is not tested for your particular problem, and it might also not work because we escape/leave the mouse-click call-stack, calling print()
method might be not possible out of user-interaction stack. 警告:此方法未针对您的特定问题进行测试,并且它可能也不起作用,因为我们转义/离开鼠标单击调用堆栈,可能无法在用户交互堆栈之外调用
print()
方法。
UPDATE: after looking in the posted jsfiddle - my assumption was correct, the browser needs some time to load and render the CSS, that is why calling the print()
right after changing iframe contents doesn't give the desired result. 更新:在查看发布的jsfiddle后 - 我的假设是正确的,浏览器需要一些时间来加载和渲染CSS,这就是为什么在更改iframe内容之后立即调用
print()
不会产生所需的结果。 There are 3.5 ways to solve that: 有3.5种方法可以解决这个问题:
iframe
element and it's children iframe
元素的事件和它的孩子 Try this one. 试试这个吧。 The problem mainly arises because the css has not been applied to the page when the print command is initiated.
问题主要是因为在启动打印命令时css尚未应用于页面。
setTimeout
is one way to solve it as others have mentioned but it is really not possible to predict how much delay you will need. setTimeout
是解决它的一种方法,正如其他人提到的那样,但实际上无法预测你需要多少延迟。 Slow internet connections will require high delays before you fire the print statement. 在触发print语句之前,缓慢的Internet连接需要很长的延迟。 The following code, however, only fires the print event after the css has been properly applied to the iframe.
但是,以下代码仅在将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();
}
});
}
});
});
As others mentioned, The problem here is that the CSS files used are external resources and browser takes time to download and cache it locally. 正如其他人提到的,这里的问题是使用的CSS文件是外部资源,浏览器需要时间下载并在本地缓存它。 Once it is cached, it would serve faster and that's why it works fine from the second click.
一旦它被缓存,它将更快地服务,这就是为什么它从第二次点击工作正常。
As Anton mentioned, setTimeout is the key here! 正如Anton所说,setTimeout是关键所在! You may probably increase the timeout seconds to make that work.
您可能会增加超时秒数以使其工作。 I tried setting it to 500ms and that worked,
我尝试将它设置为500毫秒,这是有效的,
setTimeout(function(){windowInstance.print();},500);
Use inline CSS instead. 请改用内联CSS。 Reason: When we PRINT or save as PDF if fails to fetch external css Files, So we have to use Inline css.
原因:如果我们打印或保存为PDF,如果无法获取外部css文件,那么我们必须使用内联css。 edited your file please see: jsfiddle.net/ytzcwykz/18/
编辑您的文件请参阅:jsfiddle.net/ytzcwykz/18/
Every thing is right just change the sequence. 每件事都是对的,只需改变顺序即可。 In browser debugger on first click it didn't show 'print_frame' in sources section while in second click it does (I am using chrome devtool).
在第一次单击时,它在浏览器调试器中没有在sources部分显示'print_frame',而在第二次单击时它(我使用chrome devtool)。
So load in memory frame with css attributes during onload: 因此在onload期间使用css属性加载到内存框架中:
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;
});
and onClick just append html 和onClick只是附加html
$('#print').click(function () {
var divId = 'report';
var printDivCSSpre ='<div id="printReportDiv" style="width:1000px; padding-right:20px;">';
var printDivCSSpost = '</div>';
window.frames["print_frame"].document.body.innerHTML = printDivCSSpre + document.getElementById(divId).innerHTML + printDivCSSpost;
window.frames["print_frame"].window.focus();
windowInstance.print();
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.