You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js调用window.print()新开打印页无法显示PDF问题

问题描述

在page.vue页面中使用基于vue-pdf封装的自定义PDF Reader组件嵌入PDF文档,页面设置导出按钮,点击按钮后通过window.print()方法在新开页面中导出PDF。当前原页面PDF可正常展示,但点击导出后新开的打印页面无法显示PDF内容,呈空白状态。

现有实现代码

page.vue 核心逻辑

<template>
    <button class="btn ml-1" @click="handleWindowPrint()">Export PDF</button>
    ....
    <div class="pdf-export" v-for="record in pdfRecords" :key="record.key">
        <PdfReader :documentUrl="record" @onclick-remove-pdf-btn="removePdfRecord" />
    </div>
    ....
</template>
handleWindowPrint() {
    const printPage = window.open('', '_blank')
    const pdf = document.querySelector('.pdf-export')
    const view = {
        ...
    };
    const html = Mustache.render(`${this.templateUsed}`, view);
    if (printPage) {
        printPage.document.head.innerHTML =
            '<meta charset="utf-8">\n' +
            ' <meta name="format-detection" content="telephone=no">\n' +
            ' <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">\n' +
            ' <meta name="viewport" content="width=device-width,initial-scale=1.0">\n'
        
        printPage.document.body.innerHTML = html + pdf?.outerHTML
        setTimeout(() => {
            printPage.print();
        }, 500);
    }
}

自定义PdfReader组件代码

<template>
  <div>
    <label><small>(Perview Three Page)</small></label>
    <figure class="image-item pdf-item">  
      <a >
        <pdf :key="i" :src="url"  v-for="i in numPages" :page="i"></pdf>
      </a>
    </figure>
  </div>
</template>
<script>
import pdf from "vue-pdf";

export default {
  name: "PdfReader",
  props: ["documentUrl", "removeable"],
  components: {
    pdf,
  },
  data: function () {
    return {
      url: this.documentUrl,
      numPages: 3,
    };
  },
// 此处存在语法笔误:原代码误写为</style>,应为</script>
</script>
问题根因

现有代码存在4个核心逻辑错误,直接导致打印页PDF空白:

  • 仅拷贝静态DOM结构,丢失Canvas绘制内容:vue-pdf是基于PDF.js将PDF分页绘制到<canvas>元素上实现预览的,而outerHTML只能拿到DOM标签本身,不会携带canvas上已经渲染好的像素数据,新页面拿到的canvas标签只是空壳。
  • 新页面缺失运行依赖:新开的是空白页,仅插入了基础meta标签,没有引入Vue、vue-pdf、PDF.js相关的运行资源,就算DOM结构完整,也无法重新执行组件渲染逻辑。
  • 触发打印时机错误:500ms的固定延时无法保证内容渲染完成,就算补全依赖,PDF加载、分页绘制是异步过程,未等内容绘制完成就触发打印,依然会拿到空白内容。
  • 节点获取逻辑bug:页面上.pdf-export是v-for循环生成的多元素节点,document.querySelector('.pdf-export')只会获取第一个匹配的节点,多PDF场景下会丢失后续PDF内容。
可落地修复方案

方案1:转图片插入打印页(改造成本最低,兼容性最好)

不需要在新页面重新渲染PDF组件,直接把原页面已经渲染好的PDF内容转成图片插入,彻底避免依赖缺失、渲染时机问题:

  1. 原页面PDF渲染完成后,遍历PdfReader组件内所有渲染好的canvas元素,调用canvas.toDataURL('image/png')获取每页PDF的base64位图地址
  2. 生成打印页内容时,把原来的pdf组件DOM替换成对应base64地址的<img>标签
  3. 监听所有img标签的onload事件,等全部图片加载完成后再调用printPage.print(),不需要额外引入任何依赖

核心参考代码:

handleWindowPrint() {
  const printPage = window.open('', '_blank')
  // 修复:获取所有PDF导出区域
  const pdfContainers = document.querySelectorAll('.pdf-export')
  const view = { /* 原有模板参数 */ }
  const html = Mustache.render(`${this.templateUsed}`, view);
  
  // 把每个容器里的canvas转成img
  let pdfHtml = ''
  pdfContainers.forEach(container => {
    const canvases = container.querySelectorAll('canvas')
    let containerHtml = '<div class="pdf-export">'
    canvases.forEach(canvas => {
      const imgSrc = canvas.toDataURL('image/png')
      containerHtml += `<img src="${imgSrc}" style="width:100%;page-break-after:always;">`
    })
    containerHtml += '</div>'
    pdfHtml += containerHtml
  })

  if (printPage) {
    printPage.document.head.innerHTML = `
      <meta charset="utf-8">
      <meta name="format-detection" content="telephone=no">
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
      <meta name="viewport" content="width=device-width,initial-scale=1.0">
      <style>img{max-width:100%;margin:10px 0;}</style>
    `
    printPage.document.body.innerHTML = html + pdfHtml
    // 等所有图片加载完再打印
    const imgs = printPage.document.querySelectorAll('img')
    let loadedCount = 0
    imgs.forEach(img => {
      img.onload = () => {
        loadedCount++
        if (loadedCount === imgs.length) {
          setTimeout(() => printPage.print(), 100)
        }
      }
    })
    // 没有图片的情况直接打印
    if (imgs.length === 0) {
      setTimeout(() => printPage.print(), 100)
    }
  }
}

方案2:当前页直接打印(体验最好,无需新开页)

不需要新开空白页,通过打印样式表控制打印范围,完全避免跨页面DOM拷贝的问题:

  1. 新增打印专用CSS,通过@media print媒体查询,隐藏页面上按钮、导航、侧边栏等不需要打印的元素,只保留.pdf-export区域为可见状态
  2. 确认页面上所有PDF分页都渲染完成(可监听vue-pdf的@rendered事件计数,所有页渲染完成后再触发打印)
  3. 直接调用window.print()调起打印即可,不需要做DOM拷贝操作

额外注意事项

  • 先修复PdfReader组件末尾的标签笔误,将误写的</style>改为</script>,保证组件基础运行正常
  • 如果PDF存在跨域问题,canvas转图片时会出现跨域污染报错,需要提前给PDF资源配置跨域允许头

内容的提问来源于stack exchange,提问作者Lucas Ho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 21:45:43