【问题标题】:Javascript window.print() issue on newly appended HTML新附加 HTML 上的 Javascript window.print() 问题
【发布时间】:2013-08-29 16:59:12
【问题描述】:

问题是新内容不会打印出来(多了几个元素)。

当用户单击我的打印链接时,我会在调用 window.print() 之前向文档添加更多 html。

我在打印之前使用 ajax 为一本书获取更多章节。

代码:

打印初始化:

var afterPrint = function () {

  var timer = setInterval(function () {

    afterContentPrint(); // Cleanup html (restore to initial state)
    clearInterval(timer);

  }, 900);
}
//window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;

事件打印点击:

$("#print-test").click(function (e) {

   e.preventDefault();

   beforeContentPrint(); // ajax call for additional content, finishing by calling window.print()
});

在函数 beforeContentPrint() 中:

var jqxhr = $.ajax({

   type: "GET",
   url: bookURL,

   success: function(data) {
     .....
     .....

     $(article).each(function () {
        parent.append(article);

     });
   },
   complete: function() {
     var timer = setInterval(function () {
        window.print();
     }, 900);
  }
 }

新内容明显添加到 HTML 文档中,因此它应该可以工作。但只有初始内容(在 ajax 调用之前)被提取出来进行打印。

此解决方案适用于 IE 和 Firefox(onbeforeprint 和 onafterprint)。

使用 window.matchMedia('print') 在 Chrome 中使用这种逻辑似乎可以正常工作。

【问题讨论】:

  • 打印预览或通过Ctrl+P打印是否输出所有页面?

标签: javascript jquery html ajax printing


【解决方案1】:

我不知道为什么会这样,但在 mozilla 文档中有一个解决方法;打印隐藏的 iframe,然后您无需显示即可打开本书的更多章节。 这里是链接https://developer.mozilla.org/en-US/docs/Printing

代码如下:

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>MDN Example</title>
<script type="text/javascript">
function closePrint () {
  document.body.removeChild(this.__container__);
}

function setPrint () {
  this.contentWindow.__container__ = this;
  this.contentWindow.onbeforeunload = closePrint;
  this.contentWindow.onafterprint = closePrint;
  this.contentWindow.print();
}

function printPage (sURL) {
  var oHiddFrame = document.createElement("iframe");
  oHiddFrame.onload = setPrint;
  oHiddFrame.style.visibility = "hidden";
  oHiddFrame.style.position = "fixed";
  oHiddFrame.style.right = "0";
  oHiddFrame.style.bottom = "0";
  oHiddFrame.src = sURL;
  document.body.appendChild(oHiddFrame);
}
</script>
</head>

<body>
  <p><span onclick="printPage('externalPage.html');" style="cursor:pointer;text-decoration:underline;color:#0000ff;">Print external page!</span></p>
</body>
</html>

【讨论】:

    【解决方案2】:

    1st Attempt : 尝试将 asyn:false 放入 beforeContentPrint 的 ajax 请求中,这样会先添加元素,然后再调用 print。

    var jqxhr = $.ajax({
    
       type: "GET",
       url: bookURL,
       async:false,
       success: function(data) {
         .....
         .....
    
         $(article).each(function () {
            parent.append(article);
    
         });
       },
       complete: function() {
         var timer = setInterval(function () {
            window.print();
         }, 900);
      }
     }
    

    2ndAttempt: 看看Here 如何强制执行一个又一个函数。 希望这会有所帮助。

    【讨论】:

    • OP 有 window.print 完成回调,成功后肯定会被调用......显然异步不是问题
    【解决方案3】:

    由于未显示添加的元素,因此可能有点难以确定确切的问题,但是通过附加/插入到文档中添加元素并不总是适用于所有浏览器,在最坏的情况下,您需要通过代码手动添加这些元素(document.createElement()appendChild() 等)。

    在尝试创建解决方法时,您可以尝试使用MutationObservers 来跟踪您的文章元素的更改,这有望帮助您在 DOM 正确更新时触发打印。新浏览器中的支持相当不错(您可能必须在某些情况下使用前缀,f.ex.WebKitMutationObserver),而对于旧浏览器,您可以提供回退 - 当然,这只能让您到目前为止。

    这将监视目标元素的更改并触发回调。

    基于this article的通用示例:

    var article = document.querySelector('#articleID'),
        doPrint = false,    // must be available in global/parent scope
        o,
        useFallback = (typeof MutationObserver !== 'undefined');
    
    
    if (!useFallback) {    
        o = new MutationObserver(function(mutations) {
            mutations.forEach(function(mutation) {
    
               // you can do additional filtering here
               // using the mutation object (.name, .type, ...)
    
               if (doPrint) {
                   doPrint = false;
                   window.print();
               }
           });
        });
    
        var cfg = { attributes: true, childList: true, characterData: true };
    
        o.observe(article, cfg);
    }
    

    现在观察者正在运行,您可以在成功回调中进行此修改:

    var timer;  // keep track of setTimeout so we can cancel it
    
    success: function(data) {
       ...
       ...
    
    $(article).each(function () {
    
        parent.append(article);
    
      });
    
      // after last element is added, add a "dummy" element
      doPrint = true;
    
      if (useFallback) {
         // fallback to setTimeout or other solution
      }
      else {
         parent.append('<br />');
      }
    
    }
    

    我制作了一个 online demo here 来设置观察者并添加一些元素。打开控制台查看操作。该演示可能在数据方面过于有限,无法模拟您的情况,但对于查看过程很有用。

    此处用于触发打印对话框的机制本身可以讨论是否是最好的——我只是提供一个作为示例。

    但是您可以看到当向article 添加某些内容时会触发观察者。这样你就知道 DOM 已经更新并且应该可以打印了。只有添加的最后一个元素需要触发打印,因此需要 doPrint 标志。

    如果您仍然没有成功,您将需要考虑以代码方式手动添加元素,或者可能预定义一些您在需要时注入的元素(如上所述,在不知道这里的完整场景的情况下,它必须是猜测)。

    【讨论】:

      【解决方案4】:

      看起来像 setInterval,clearInterval 是什么让你搞砸了。更改为 setTimeout 并删除 afterprint 函数中的 clearInterval 。我制作了一个适用于 FF 和 IE9 的小提琴。 Fiddle

          complete: function() {
              var timer = setTimeout(function () {
              window.print();
            }, 900);
          }
      

      【讨论】:

      • 我确实在调用 print 前几秒钟使用了 setTimeout,但它不起作用。我还尝试通过使用success: function(data) {} for ajax 和complete: function() {} for window.print 来分离这两个进程,但这也没有解决它。嗯。
      猜你喜欢
      • 2015-07-30
      • 1970-01-01
      • 2021-07-09
      • 2016-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-17
      相关资源
      最近更新 更多