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

如何为JavaScript生成的<svg>内容添加仅展示一次的自定义标签标题?

问题根源

你把Recipes自定义标签的插入逻辑放在了遍历每个单词的while循环内部,每处理一个单词就会执行一次插入操作,才会出现输入多个字符/单词时标签重复生成的问题。

修复方案

  1. 将标签插入逻辑移到循环外部,仅在用户输入内容不为空时执行一次
  2. 调整用户输入内容的初始y轴坐标,避免和上方标签重叠
  3. 输入内容清空时,标签会自动不渲染,符合你的需求

修改后的完整代码

import "./styles.css";
import { useState } from "react";

export default function App() {
  const [dummyText, setDummyText] = useState("");

  const updateContent = (e) => {
    setDummyText(e.target.value);
  };

  function calculateWordWidths() {
    const words = dummyText.split(/\s+/);
    let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    let text = document.createElementNS("http://www.w3.org/2000/svg", "text");
    text.style =
      "font: 13pt LiberationSans, Helvetica, Arial, sans-serif; white-space: pre;";
    svg.appendChild(text);
    document.body.appendChild(svg);

    const wordsWithComputedWidth = words.map((word) => {
      text.textContent = word;
      return { word, width: text.getComputedTextLength() };
    });

    text.textContent = "\u00A0"; // Unicode space
    const spaceWidth = text.getComputedTextLength();

    document.body.removeChild(svg);

    return { wordsWithComputedWidth, spaceWidth };
  }

  let { wordsWithComputedWidth, spaceWidth } = calculateWordWidths();

  const content = [[]];
  let xPos = 0;
  let yPos = 60;
  let page = 1;

  let i = 0,
    len = wordsWithComputedWidth.length;

  // 新增:仅当有输入内容时,在第一页顶部插入一次标签
  if (dummyText.trim().length > 0) {
    content[0].push(
      <text
        x="0"
        y="24"
        key="recipe-label"
        style={{
          font: "bold 17pt LiberationSans, Helvetica, Arial, sans-serif",
          whiteSpace: "pre"
        }}
      >
        Recipes
      </text>
    );
    // 调整用户内容的起始y坐标,避免和标签重叠
    yPos = 48;
  }

  while (i < len) {
    if (yPos > 97) {
      content.push([]);
      page++;
      xPos = 0;
      yPos = 16;
    }

    //Push new text elements to the content array
    content[page - 1].push(
      <text
        x={xPos}
        y={yPos}
        key={i}
        style={{
          font: "13pt LiberationSans, Helvetica, Arial, sans-serif",
          whiteSpace: "pre"
        }}
      >
        {wordsWithComputedWidth[i].word}
      </text>
    );
    xPos += wordsWithComputedWidth[i].width + spaceWidth;
    if (xPos > 100) {
      yPos += 16;
      xPos = 0;
    }

    i++;
  }

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <div className="container">
        <div className="content">
          <div>Content</div>
          <textarea
            rows="6"
            cols="24"
            onChange={(e) => updateContent(e)}
            style={{ marginTop: "50px" }}
          />
        </div>
        <div className="preview">
          <div>Preview</div>
          <>
            {content.map((resumePage, idx) => (
              <svg
                viewBox="0 0 595.28 100.89"
                xmlns="http://www.w3.org/2000/svg"
                style={{ border: "1px solid #aaa" }}
                key={idx}
              >
                {content[idx]}
              </svg>
            ))}
          </>
        </div>
      </div>
    </div>
  );
}

修改后仅在用户有输入时,标签会在第一页顶部出现一次,textarea内容清空时标签自动消失,不会重复生成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 04:48:03