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

React+TypeScript中window.print触发页面冻结问题求助

问题

在React+TypeScript项目中,尝试打印模态框内带有数据的div(id='printablediv'),点击模态框上的打印按钮时执行以下Print函数:

const Print = () => {
    let printContents = document.getElementById('printablediv')?.innerHTML!;
    let originalContents = document.body.innerHTML;
    document!.body!.innerHTML! = printContents;
    window.print();
    document.body.innerHTML = originalContents;
    setIsModalOpen(false)
}

点击打印后,无论完成打印还是取消打印,页面都会冻结,无法进行任何操作,必须刷新页面才能恢复。不希望使用react-to-print这类第三方库。

补充:Print函数的调用方式如下:

<TicketModal
    isOpen={isTicketModalOpen}
    onAnulla={onCloseTicketModal}
    onPrint={Print}
    code={createResponseCode}
    pin={createResponsePin}
    id={user.uid}
    currency={createResponseCurrency}
    amount={createResponseAmount}
/>

onPrint属性关联到模态框内的打印按钮:

<Button size="lg"
   variant="primary"
   className='ticket-modal-card__button'
   onClick={onPrint}
>
   Print Ticket
</Button>

解决思路与修复方案

问题根源

直接替换document.body.innerHTML会彻底破坏React维护的虚拟DOM与真实DOM的绑定关系,同时移除了所有原DOM节点上的事件监听、组件状态关联。即便后续把innerHTML还原,也无法恢复这些绑定,导致页面失去交互能力。

修复代码

改用临时元素承载打印内容,避免修改原body的DOM结构:

const Print = () => {
    const printDiv = document.getElementById('printablediv');
    if (!printDiv) return;

    // 创建临时容器
    const tempContainer = document.createElement('div');
    // 复制目标div的内容和基础样式,保证打印显示正常
    tempContainer.innerHTML = printDiv.innerHTML;
    tempContainer.style.position = 'absolute';
    tempContainer.style.top = '0';
    tempContainer.style.left = '0';
    tempContainer.style.width = '100%';
    tempContainer.style.height = '100%';
    tempContainer.style.background = 'white';
    tempContainer.style.zIndex = '9999';

    // 保存原body的所有子元素,避免直接替换innerHTML
    const originalBodyChildren = Array.from(document.body.children);
    // 清空body并添加临时容器
    document.body.innerHTML = '';
    document.body.appendChild(tempContainer);

    // 打印完成/取消后的恢复逻辑
    const handlePrintEnd = () => {
        // 移除临时容器
        tempContainer.remove();
        // 恢复原body的所有子元素
        originalBodyChildren.forEach(child => document.body.appendChild(child));
        // 关闭模态框
        setIsModalOpen(false);
        // 移除事件监听,防止重复绑定
        window.removeEventListener('afterprint', handlePrintEnd);
    };

    // 监听打印结束事件
    window.addEventListener('afterprint', handlePrintEnd);
    // 触发打印
    window.print();
}

关键改进点

  • 不直接替换document.body.innerHTML,而是保存并恢复原body的子元素,保留React的DOM绑定关系
  • 使用临时容器单独承载打印内容,打印完成后直接移除,不影响原页面结构
  • 通过afterprint事件确保无论打印完成还是取消,都能正确恢复页面状态
  • 给临时容器设置基础样式,保证打印内容正常显示

内容的提问来源于stack exchange,提问作者Oren Papa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 18:01:25