如何在 iPad 上使用 Javascript 打印 iFrame 的内容?

发布于 2024-12-07 15:30:05 字数 635 浏览 1 评论 0原文

打印 iFrame 的内容似乎已经成为跨浏览器解决的一个具有挑战性的问题。在测试了很多方法(其中一些也可以在这个网站上找到)之后,我当前的方法似乎在跨浏览器上运行得很好,如下所示:

function printUrl( elem, url ) {
    $( '#' + elem ).append( "<iframe style='border: none; width: 0; height: 0; margin: 0; padding: 0;' src='" + url + "' id='printFrame'></iframe>" );

    $( '#printFrame' ).load( function() {
        var w = ( this.contentWindow || this.contentDocument.defaultView );
        w.focus();
        w.print();
    } );
}

使用 iPad 时,此代码只有一个小问题。 iPad 打印包含 iFrame 的页面,而不是 iFrame 的内容。不过,Mac 上的 Safari 可以正确打印 iFrame 的内容。

有人已经解决了这个问题并能够在 iPad 上打印 iFrame 的内容吗?

Printing the contents of an iFrame already seemed a challenging problem to solve cross-browser. After testing a lot of approaches (some of which also found on this site), my current approach seems to work quite good cross-browser and looks like this:

function printUrl( elem, url ) {
    $( '#' + elem ).append( "<iframe style='border: none; width: 0; height: 0; margin: 0; padding: 0;' src='" + url + "' id='printFrame'></iframe>" );

    $( '#printFrame' ).load( function() {
        var w = ( this.contentWindow || this.contentDocument.defaultView );
        w.focus();
        w.print();
    } );
}

There is only a slight problem with this code when using an iPad. The iPad prints the page which contains the iFrame, instead of the contents of the iFrame. Safari on Mac correctly prints the contents of the iFrame, though.

Has anyone already solved this problem and been able to print the contents of an iFrame on an iPad?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

北方的韩爷 2024-12-14 15:30:05

好吧,首先。我没有解决问题。我创建了一个解决方法,实际上伪造了我想要实现的目标。

因为 iPad / iPhone 简单地打印父页面,所以我将完整的正文包装在一个新的 div 中,然后附加 iFrame 和一些样式表,以确保打印的文档仅包含 iFrame:

function printUrl( url ) {
    $newBody = "<div class='do_not_print_this'>"
                + $( 'body' ).html()
                + "</div>"
                + "<iframe style='border: none; 0; width: 100%; margin: 0; padding: 0;' src='" + url + "' class='printFrame'></iframe>"
                + "<style type='text/css' media='all'>.printFrame { position: absolute; top: -9999999px; left: -99999999px; }</style>"
                + "<style type='text/css' media='print'>.do_not_print_this { display: none; } .printFrame { top: 0; left: 0; }</style>";
    $( 'body' ).html( $newBody );

    $( '.printFrame' ).load( function() {
        var w = ( this.contentWindow || this.contentDocument.defaultView );
        w.focus();
        w.print();
    } );
}

在普通视图中隐藏浏览器的 iframe使用绝对定位完成,使用无显示或可见性隐藏在最终打印中引入了奇怪的行为。

是的,它很丑。然而,这是目前我能想到的唯一可行的选择。如果你们中有人提出更好的解决方案,请告诉我。

Okay, first of all. I did not solve the problem. I created a work-around that actually fakes what I want to achieve.

Because the iPad / iPhone simple prints the parent page, I wrap the complete body in a new div, then append the iFrame and some stylesheets which make sure that the printed document only contains the iFrame:

function printUrl( url ) {
    $newBody = "<div class='do_not_print_this'>"
                + $( 'body' ).html()
                + "</div>"
                + "<iframe style='border: none; 0; width: 100%; margin: 0; padding: 0;' src='" + url + "' class='printFrame'></iframe>"
                + "<style type='text/css' media='all'>.printFrame { position: absolute; top: -9999999px; left: -99999999px; }</style>"
                + "<style type='text/css' media='print'>.do_not_print_this { display: none; } .printFrame { top: 0; left: 0; }</style>";
    $( 'body' ).html( $newBody );

    $( '.printFrame' ).load( function() {
        var w = ( this.contentWindow || this.contentDocument.defaultView );
        w.focus();
        w.print();
    } );
}

Hiding the iframe for the browser in the normal view is done using absolute positioning, using display on none or visibility hidden introduced weird behavior in the final print.

Yes, it's ugly. However, this is currently the only option I can think of which works. If any of you come up with a better solution, please let me know.

守望孤独 2024-12-14 15:30:05

这是一个在常青浏览器和当前版本的 iOS 上跨平台工作的函数:

function printElement(divid, title)
{   
  var contents = document.getElementById(divid).innerHTML;
  var frame1 = document.createElement('iframe');
  frame1.name = "frame1";
  frame1.style.position = "absolute";
  frame1.style.top = "-1000000px";
  document.body.appendChild(frame1);
  var frameDoc = frame1.contentWindow ? frame1.contentWindow : frame1.contentDocument.document ? frame1.contentDocument.document : frame1.contentDocument;
  frameDoc.document.open();
  frameDoc.document.write('<html><head><title>' + title + '</title>');
  frameDoc.document.write('</head><body style="font-family: Arial, Helvetica, sans; font-size: 14px; line-height: 20px">');
  frameDoc.document.write('<h1>' + title + '</h1>');
  frameDoc.document.write(contents);
  frameDoc.document.write('</body></html>');
  frameDoc.document.close();

  setTimeout(function () {
    window.frames["frame1"].focus();
    window.frames["frame1"].print();
  }, 500);

  //Remove the iframe after a delay of 1.5 seconds
  //(the delay is required for this to work on iPads)
  setTimeout(function () {
     document.body.removeChild(frame1);
  }, 1500);
  return false;
}

这​​是基于这个答案小修改(重要的是,必须删除 document.body.removeChild(frame1); 行才能在 iOS 上打印。)

Here's a function that works cross-cross platform on evergreen browsers and the current versions of iOS:

function printElement(divid, title)
{   
  var contents = document.getElementById(divid).innerHTML;
  var frame1 = document.createElement('iframe');
  frame1.name = "frame1";
  frame1.style.position = "absolute";
  frame1.style.top = "-1000000px";
  document.body.appendChild(frame1);
  var frameDoc = frame1.contentWindow ? frame1.contentWindow : frame1.contentDocument.document ? frame1.contentDocument.document : frame1.contentDocument;
  frameDoc.document.open();
  frameDoc.document.write('<html><head><title>' + title + '</title>');
  frameDoc.document.write('</head><body style="font-family: Arial, Helvetica, sans; font-size: 14px; line-height: 20px">');
  frameDoc.document.write('<h1>' + title + '</h1>');
  frameDoc.document.write(contents);
  frameDoc.document.write('</body></html>');
  frameDoc.document.close();

  setTimeout(function () {
    window.frames["frame1"].focus();
    window.frames["frame1"].print();
  }, 500);

  //Remove the iframe after a delay of 1.5 seconds
  //(the delay is required for this to work on iPads)
  setTimeout(function () {
     document.body.removeChild(frame1);
  }, 1500);
  return false;
}

This is based on this answer with minor modifications (Importantly the line document.body.removeChild(frame1); had to be removed to allow for printing on iOS.)

难忘№最初的完美 2024-12-14 15:30:05

我使用了 @d13 答案并做了一些修改。因为 window.frames["frame1"] 不是有效的对象。 window.frames 是一个类似数组的对象。

MDN 文档

返回窗口本身,它是一个类似数组的对象,列出了当前窗口的直接子框架...

window.frames 伪数组中的每一项表示与给定的 或 的内容相对应的 Window 对象,而不是frame或iframe DOM元素(即window.frames[0]与document相同.getElementsByTagName("iframe")[0].contentWindow)。

所以我使用了以下方法:

export function printHtml(html: string) {
  // Create an iframe element
  const iframe = document.createElement('iframe');
  iframe.style.position = 'absolute';
  iframe.style.width = '0';
  iframe.style.height = '0';
  iframe.style.border = 'none';

  // Append the iframe to the body
  document.body.appendChild(iframe);

  // Write the content to the iframe
  const doc = iframe.contentWindow?.document;
  if (doc) {
    doc.open();
    doc.write(html);
    doc.close();
  }

  // we need to use the print this way to be able to print in phones
  setTimeout(() => {
    window[0].focus();
    window[0].print();
    setTimeout(() => {
      document.body.removeChild(iframe); // Clean up by removing
    }, 500);
  }, 500);
}

I used @d13 answer with a little bit modification. because window.frames["frame1"] is not a valid object. window.frames is an array like object.

MDN Docs:

Returns the window itself, which is an array-like object, listing the direct sub-frames of the current window...

Each item in the window.frames pseudo-array represents the Window object corresponding to the given 's or 's content, not the frame or iframe DOM element (i.e., window.frames[0] is the same thing as document.getElementsByTagName("iframe")[0].contentWindow).

So I have used below method:

export function printHtml(html: string) {
  // Create an iframe element
  const iframe = document.createElement('iframe');
  iframe.style.position = 'absolute';
  iframe.style.width = '0';
  iframe.style.height = '0';
  iframe.style.border = 'none';

  // Append the iframe to the body
  document.body.appendChild(iframe);

  // Write the content to the iframe
  const doc = iframe.contentWindow?.document;
  if (doc) {
    doc.open();
    doc.write(html);
    doc.close();
  }

  // we need to use the print this way to be able to print in phones
  setTimeout(() => {
    window[0].focus();
    window[0].print();
    setTimeout(() => {
      document.body.removeChild(iframe); // Clean up by removing
    }, 500);
  }, 500);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文