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

ReactJS中JSX实现无弹窗直接打印页面/PDF的方案

ReactJS 实现无弹窗直接打印票据(公交/电影票)

核心说明

浏览器原生的window.print()默认会弹出打印设置窗口,这是浏览器的安全限制,网页端无法直接绕过。要实现无弹窗静默打印,需要用户提前在浏览器设置中允许当前站点的静默打印权限,或者使用Electron等桌面应用框架调用系统打印API。

下面给出基于React JSX的票据打印完整实现,包含指定区域打印、自定义打印样式,以及模拟静默打印的可行方案。

完整代码示例

import React, { useRef } from "react";
import styles from "../Components/ReactPdfPrint.module.css";
import "bootstrap/dist/css/bootstrap.min.css";

const handlePrint = (printRef) => {
  if (!printRef) return;

  // 创建打印窗口
  const printWindow = window.open("", "_blank");
  // 复制目标区域的HTML和页面样式
  const printContent = printRef.innerHTML;
  const styleSheets = Array.from(document.styleSheets)
    .map(sheet => {
      try {
        return sheet.cssText || Array.from(sheet.cssRules).map(rule => rule.cssText).join('');
      } catch (e) {
        // 跨域样式无法访问,直接跳过
        return '';
      }
    })
    .join('');

  // 写入打印窗口内容
  printWindow.document.write(`
    <html>
      <head>
        <title>票据打印</title>
        <style>
          ${styleSheets}
          /* 适配打印的样式 */
          body { margin: 0; padding: 10px; }
          @media print {
            @page { size: auto; margin: 0; }
            body { margin: 0; }
          }
        </style>
      </head>
      <body>${printContent}</body>
    </html>
  `);

  printWindow.document.close();
  
  // 等待内容加载完成后触发打印
  printWindow.onload = () => {
    // 尝试静默打印(需浏览器提前授权)
    printWindow.print();
    // 打印完成后自动关闭窗口
    setTimeout(() => printWindow.close(), 100);
  };
};

const ReactPdfPrint = () => {
  const ticketRef = useRef(null);

  return (
    <>
      {/* 票据区域,用ref标记为打印目标 */}
      <div ref={ticketRef} className={styles.ticket}>
        <img src="./ticketLogo.jpg" alt="公交票务" height="30px" width="30px" />
        <p className={styles.centered}>
          公交乘车凭证
          <br />
          起点:XX地铁站
          <br />
          终点:XX商圈站
        </p>
        <table>
          <thead>
            <tr>
              <th className={styles.quantity}>票种</th>
              <th className={styles.description}>详细信息</th>
              <th className={styles.price}>金额</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td className={styles.quantity}>1</td>
              <td className={styles.description}>成人单程票</td>
              <td className={styles.price}>¥2.00</td>
            </tr>
            <tr>
              <td className={styles.quantity} />
              <td className={styles.description}>总金额</td>
              <td className={styles.price}>¥2.00</td>
            </tr>
          </tbody>
        </table>
        <p className={styles.centered}>
          乘车时间:2024-05-20 08:30
          <br />
          票号:BUS-20240520-00123
        </p>
      </div>
      <p className="centered">
        感谢使用公共交通!
      </p>
      {/* 打印触发按钮 */}
      <button 
        id="btnPrint" 
        className={styles.container} 
        onClick={() => handlePrint(ticketRef.current)}
      >
        打印票据
      </button>
    </>
  );
};

export default ReactPdfPrint;

关键细节说明

  1. 指定打印区域:通过useRef获取票据DOM元素,仅打印目标区域内容,避免打印整个页面的无关元素。
  2. 自定义打印样式:在打印窗口中注入原页面样式,并添加@media print媒体查询,确保票据排版适配打印纸尺寸。
  3. 静默打印的实现限制:
    • 网页端必须用户手动在浏览器设置中开启「允许此站点静默打印」权限,否则仍会弹出打印设置窗口。
    • 桌面应用场景(如Electron)可替换为以下代码实现真正无弹窗打印:
      // Electron渲染进程代码
      const { ipcRenderer } = require('electron');
      ipcRenderer.send('print-silent', printContent);
      
      // Electron主进程代码
      const { ipcMain } = require('electron');
      ipcMain.on('print-silent', (event) => {
        mainWindow.webContents.print({ silent: true, printBackground: true });
      });
      

配套样式文件参考(ReactPdfPrint.module.css)

.ticket {
  width: 300px;
  border: 1px solid #000;
  padding: 15px;
  margin: 20px auto;
  font-family: Arial, sans-serif;
}

.centered {
  text-align: center;
  margin: 10px 0;
}

table {
  width: 100%;
  border-collapse: collapse;
  margin: 15px 0;
}

th, td {
  border: 1px solid #000;
  padding: 5px;
  text-align: center;
}

.description {
  text-align: left;
}

.container {
  display: block;
  margin: 0 auto;
  padding: 8px 16px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.container:hover {
  background-color: #0056b3;
}

内容的提问来源于stack exchange,提问作者Manthan Vaja

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 23:27:42