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

如何获取p元素实际宽度以动态设置react-pdf的PDF宽度?

解决React中获取p元素宽度始终不变的问题

问题核心

你试图获取页面中p元素的宽度,用于动态设置react-pdf生成的PDF宽度,但无论输入内容长短,点击按钮打印的宽度值始终固定,没有随内容变化更新。

原因分析

  1. useEffect仅执行一次:你的useEffect没有设置依赖数组,只会在组件首次挂载时计算一次宽度,之后props.preview(内容)、props.font(字体)等影响宽度的变量变化时,不会重新计算并更新width状态。
  2. 依赖旧状态值:点击按钮时打印的是state中存储的width,而这个值只在挂载时被赋值,后续内容变化后没有更新,所以始终显示初始值。
  3. 目标元素样式缺失:用于获取宽度的p元素仅设置了字体类,未明确设置字体大小,可能因继承样式导致内容变化时宽度无明显变化。

修复方案

1. 让useEffect随依赖项更新宽度

补全useEffect的依赖数组,确保影响元素宽度的变量变化时,重新计算宽度:

const Preview = (props) => {
  const ref = useRef();
  const [width, setWidth] = useState(0);

  useEffect(() => {
    // 确保元素存在再获取宽度
    if (ref.current) {
      setWidth(ref.current.offsetWidth);
    }
  }, [props.preview, props.font, props.sizeClass]); // 加入所有影响宽度的依赖项

  // ... 其他代码
};

2. 点击时直接获取实时宽度

不需要依赖state存储宽度,点击按钮时直接从ref中读取当前元素的实时宽度,避免state更新不及时的问题:

const getDimHandler = (e) => {
  e.preventDefault();
  if (ref.current) {
    console.log(ref.current.offsetWidth); // 直接获取最新宽度
  }
};

3. 确保目标p元素样式正确

给用于获取宽度的p元素设置和预览区一致的字体大小,保证内容变化时宽度能正确反映:

<p ref={ref} id={props.sizeClass} className={`${props.font} text-[8rem]`}>
  {props.preview}
</p>

4. 处理自定义字体加载延迟

如果使用了自定义字体,字体加载完成前计算的宽度可能不准确,可以等待字体加载完成后再获取宽度:

useEffect(() => {
  const updateWidthAfterFontLoaded = async () => {
    await document.fonts.ready; // 等待所有字体加载完成
    if (ref.current) {
      setWidth(ref.current.offsetWidth);
    }
  };
  updateWidthAfterFontLoaded();
}, [props.preview, props.font, props.sizeClass]);

修改后的完整示例代码

const Preview = (props) => {
  const ref = useRef();
  const [width, setWidth] = useState(0);

  useEffect(() => {
    const updateWidthAfterFontLoaded = async () => {
      await document.fonts.ready;
      if (ref.current) {
        setWidth(ref.current.offsetWidth);
      }
    };
    updateWidthAfterFontLoaded();
  }, [props.preview, props.font, props.sizeClass]);

  const MyDoc = () => {
    Font.register({
      family: "broadsheet",
      src: broadsheet,
    });
    Font.register({
      family: "jost",
      src: jost,
    });
    Font.register({
      family: "texgyreheros",
      src: texgyreheros,
    });
    return (
      <Document>
        <Page
          size={[width, 20000]} // 使用动态获取的宽度
          style={{
            fontFamily: props.pdfFont,
            fontSize: props.size,
          }}
        >
          <View style={{ margin: "auto", lineHeight: "0" }}>
            <Text>{props.preview}</Text>
          </View>
        </Page>
      </Document>
    );
  };

  const getDimHandler = (e) => {
    e.preventDefault();
    if (ref.current) {
      console.log(ref.current.offsetWidth);
    }
  };

  return (
    <>
      <Container className="bg-white p-5 mb-5">
        <p className={`${props.font} text-[8rem]`}>{props.preview}</p>
      </Container>

      <p ref={ref} id={props.sizeClass} className={`${props.font} text-[8rem]`}>
        {props.preview}
      </p>

      <PDFDownloadLink
        document={<MyDoc />}
        fileName="somename.pdf"
        className="bg-violet-500 hover:bg-violet-700 text-white font-bold py-2 px-4 rounded-full"
      >
        {({ blob, url, loading, error }) =>
          loading ? "Preparing document..." : "Download"
        }
      </PDFDownloadLink>
      <button onClick={getDimHandler}>Get Dims</button>
    </>
  );
};

export default Preview;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 11:22:30