首页 > 解决方案 > 自定义useOneLineText React Hook,可调整字体大小并始终将文本保持在一行

问题描述

我正在尝试创建一个自定义钩子,它将文本保持在一行,这就是我到目前为止所得到的:

import { useEffect, useState, useRef } from "react";

export default function useOneLineText(initialFontSize, text) {
  const containerRef = useRef(null);
  const [adjustedFontSize, setAdjustedFontSize] = useState(initialFontSize);

  useEffect(() => {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    const containerWidth = containerRef.current.getBoundingClientRect().width;
    let currentFontSize = initialFontSize;

    do {
      ctx.font = `${currentFontSize}px "Lato"`;
      currentFontSize -= 1;
    } while (containerWidth < ctx.measureText(text).width);

    setAdjustedFontSize(currentFontSize);
  }, []);

  return { containerRef, adjustedFontSize, text };
}

以及用法:

import React, { useState } from "react";
import "./style.css";
import useOneLineText from "./useOneLineText";

const initialFontSize = 32;

export default function App() {
  const [shortText, setShortText] = useState("Hello Peaceful World!");
  const { containerRef, adjustedFontSize, text } = useOneLineText(
    initialFontSize,
    shortText
  );

  return (
    <div>
      <h1
        ref={containerRef}
        style={{ width: "100px", fontSize: `${adjustedFontSize}px` }}
      >
        {text}
      </h1>

      <h1 style={{ width: "100px", fontSize: `${initialFontSize}px` }}>
        Hello Cruel World!
      </h1>

      <button onClick={() => setShortText("Hello World!")}>Remove Peace</button>
    </div>
  );
}

我想知道为什么尝试使用Remove Peace按钮更改文本时我的字体没有更新。我也不确定在 useEffect 中循环并将字体大小减小 1 是否是最好的方法,是否可以在没有循环的情况下计算调整后的字体大小?这是我的工作示例

标签: javascriptreactjsreact-hooks

解决方案


好吧,您的代码已经可以正常工作了。从您的示例中,初始字体大小 32px 在安装时更改为 10px。此外,您的效果仅在安装时运行。如果不删除这个词,它也已经满足containerWidth < ctx.measureText(text).width.

如果您希望在 containerWidth 或 textWidth 更改时发生效果,那么您可以添加更多状态并将它们添加到您的 useEffect 依赖项列表中。

const [container, setContainerState] = useState(null);
const [textWidth, setTextWidth] = useState(null);

useEffect(() => {
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");
  const refWidth = containerRef.current.getBoundingClientRect().width;
  let currentFontSize = initialFontSize;

  if (
    textWidth !== ctx.measureText(text).width ||
    containerWidth !== refWidth
  ) { 
    do {
      ctx.font = `${currentFontSize}px "Lato"`;
      currentFontSize -= 1;
    } while (refWidth < ctx.measureText(text).width);
    setContainerWidth(containerWidth);
    setTextWidth(textWidth);
    setAdjustedFontSize(currentFontSize);
  }
}, [textWidth, containerWidth]);

为了更快地调整字体大小,您可以从使用二分搜索帮助您更快找到正确宽度的 jquery 问题中查看此答案?

自动调整大小的动态文本


推荐阅读