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

如何使用React实现类似Google Docs的自动分页功能

实现类Google Docs自动分页预览的React方案

方案一:状态驱动+手动分页计算

这是灵活性最高的方案,完全通过React状态管理内容,结合DOM测量实现精准分页:

  1. 统一状态管理:将左面板表单的所有输入数据维护在全局状态(如useState、useReducer),表单更新时同步状态,预览组件完全从状态取数渲染。
  2. 测量组件高度:给每个展示组件添加ref,用useLayoutEffect在组件渲染完成后获取实际DOM高度,避免布局抖动。
  3. 编写分页逻辑:遍历所有展示组件的高度,累加至页面容器高度阈值时,将组件分组为不同“页面”数组。
  4. 渲染分页内容:根据分组结果渲染多个Page容器,每个容器对应一组展示组件。
  5. 监听更新:在表单数据变化、窗口大小改变或异步内容(如图片)加载完成时,重新执行分页计算。

示例代码片段:

import { useState, useRef, useLayoutEffect } from 'react';

const PreviewPage = ({ children }) => (
  <div style={{
    width: '210mm',
    minHeight: '297mm',
    padding: '15mm',
    boxSizing: 'border-box',
    border: '1px solid #eee',
    marginBottom: '20px'
  }}>
    {children}
  </div>
);

const DocumentPreview = ({ formData }) => {
  const [pages, setPages] = useState([]);
  const componentRefs = useRef([]);
  // 页面可用高度:A4总高减去上下内边距,需根据实际需求换算单位
  const pageAvailableHeight = (297 - 30) * 3.7795;

  // 生成展示组件列表
  const contentComponents = [
    <Component1 data={formData.comp1} ref={el => componentRefs.current[0] = el} />,
    <Component2 data={formData.comp2} ref={el => componentRefs.current[1] = el} />,
    // ... 其他8个组件
  ];

  useLayoutEffect(() => {
    const calculatePages = () => {
      const newPages = [];
      let currentPage = [];
      let currentHeight = 0;

      componentRefs.current.forEach((el, index) => {
        if (!el) return;
        const height = el.offsetHeight;
        // 当前页添加组件后超阈值时,新建一页
        if (currentHeight + height > pageAvailableHeight && currentPage.length > 0) {
          newPages.push(currentPage);
          currentPage = [];
          currentHeight = 0;
        }
        currentPage.push(contentComponents[index]);
        currentHeight += height;
      });

      if (currentPage.length > 0) newPages.push(currentPage);
      setPages(newPages);
    };

    calculatePages();
    window.addEventListener('resize', calculatePages);
    return () => window.removeEventListener('resize', calculatePages);
  }, [formData]);

  return (
    <div>
      {pages.map((page, index) => (
        <PreviewPage key={index}>{page}</PreviewPage>
      ))}
    </div>
  );
};

方案二:CSS Columns自动布局

如果不需要极致的分页控制,纯CSS就能实现内容自动流动的分页效果,代码量极少:

  1. 设置容器样式:给预览容器添加CSS多列布局,列宽设为页面宽度,列间距设为分页间隔。
  2. 控制组件拆分:给不希望被拆分的展示组件添加break-inside: avoid样式,避免组件跨页断裂。

示例CSS:

.preview-container {
  columns: 1;
  column-width: 210mm; /* A4页面宽度 */
  column-gap: 20px; /* 页面之间的间隔 */
}

.page-section {
  break-inside: avoid; /* 禁止组件跨页 */
  width: 100%;
  margin-bottom: 16px;
}

.preview-page {
  width: 210mm;
  min-height: 297mm;
  padding: 15mm;
  box-sizing: border-box;
  border: 1px solid #eee;
  margin-bottom: 20px;
}

React组件示例:

const DocumentPreview = ({ formData }) => {
  return (
    <div className="preview-container">
      <div className="preview-page">
        <Component1 data={formData.comp1} className="page-section" />
        <Component2 data={formData.comp2} className="page-section" />
        {/* ... 其他8个组件 */}
      </div>
    </div>
  );
};

该方案无需JS计算,由浏览器处理内容流动,适合内容结构简单的场景;缺点是对分页位置的控制较弱,无法强制指定内容归属页面。

方案三:使用React文档渲染库

如果需要复杂文档功能(如页眉页脚、页码、精确分页规则),可借助成熟第三方库减少重复造轮子:

  • @react-pdf/renderer:虽主打PDF生成,但支持浏览器内类页面预览,内置完善分页逻辑、页眉页脚配置,适合需严格遵循打印格式的场景。
  • react-page:提供拖拽式页面编辑能力,同时支持自动分页,适合可视化编辑+预览的场景。

这类库封装了复杂的分页、排版逻辑,无需自行处理高度计算和内容拆分,但需学习库的API,且可能增加打包体积。


内容的提问来源于stack exchange,提问作者Sivanesh S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 16:45:24