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

React(NextJS)打印组件二次点击报错NotFoundError求助

解决NextJS中打印React组件第二次点击报错的问题

你遇到的问题是首次点击打印能正常预览PDF,第二次点击就抛出NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node错误,根源在于你直接操作document.body.innerHTML的方式破坏了React的DOM管理机制。

错误原因

  • React通过虚拟DOM追踪真实DOM的变化,你直接替换document.body.innerHTML会完全清除React管理的所有节点,包括Sheet组件的DOM结构
  • 第一次打印后恢复originalContents,页面看起来正常,但React的虚拟DOM和真实DOM已经不同步
  • 第二次点击打印时,Sheet组件的状态变化触发React更新,此时React尝试操作已被篡改的DOM,找不到对应的子节点,从而抛出错误

解决方案

用你已经导入的react-to-print库,它专门处理React组件的打印,不会破坏React的DOM结构。具体修改如下:

修改后的完整代码

import { Divider } from "@tremor/react"
import { useRef } from "react"
import React from "react"
import { useReactToPrint } from "react-to-print"

import { Button } from "@/components/ui/button"
import { Sheet, SheetContent, SheetHeader, SheetTrigger } from "@/components/ui/sheet"

import { BuildingInformation } from "./components/building-information"
import { EnergyEfficiency } from "./components/energy-efficiency"
import { FinancialAnalysis } from "./components/financial-analysis"
import { Intro } from "./components/Intro"
import { Modernization } from "./components/modernization"

export const DataReporting = () => {
  // 创建ref绑定到要打印的div
  const printRef = useRef(null)

  // 使用react-to-print创建打印函数
  const handlePrint = useReactToPrint({
    content: () => printRef.current,
    // 可选:打印后可添加回调,比如关闭Sheet(需根据Sheet组件API实现)
    onAfterPrint: () => {
      // 示例:若用useState控制Sheet显示,可在此处设置状态为false
      // setSheetOpen(false)
    }
  })

  return (
    <Sheet>
      <SheetTrigger>
        <Button variant={"ghost"}>Holen Sie sich Ihren Bericht</Button>
      </SheetTrigger>
      <SheetContent
        side={"bottom"}
        className='h-full m-auto overflow-y-auto print:overflow-y-auto sm:w-screen lg:w-fit'
      >
        <SheetHeader>
          <Button className='w-fit z-20 mr-auto bg-blue-700 hover:bg-blue-600' onClick={handlePrint}>
            Herunterladen
          </Button>
          <Divider />
        </SheetHeader>
        {/* 把ref绑定到这个要打印的div */}
        <div ref={printRef}>
          <Intro />
          <BuildingInformation />
          <Modernization />
          <EnergyEfficiency />
          <FinancialAnalysis />
        </div>
      </SheetContent>
    </Sheet>
  )
}

替代方案(原生JS方式,不推荐)

如果必须用原生JS实现,可以创建临时iframe承载打印内容,避免干扰主页面DOM:

const print = () => {
  const printContents = document.getElementById("div")?.innerHTML
  if (!printContents) return

  const iframe = document.createElement('iframe')
  iframe.style.display = 'none'
  document.body.appendChild(iframe)

  const doc = iframe.contentDocument || iframe.contentWindow.document
  doc.write(`
    <html>
      <head>
        <title>打印内容</title>
        <!-- 引入你的样式文件 -->
        <link rel="stylesheet" href="/path/to/your/styles.css">
      </head>
      <body>${printContents}</body>
    </html>
  `)
  doc.close()

  iframe.contentWindow?.print()

  // 打印完成后移除iframe
  setTimeout(() => {
    document.body.removeChild(iframe)
  }, 1000)
}

内容的提问来源于stack exchange,提问作者Ala Eddine Menai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 05:34:52