如何为JavaScript生成的<svg>内容添加仅展示一次的自定义标签标题?
问题根源
你把Recipes自定义标签的插入逻辑放在了遍历每个单词的while循环内部,每处理一个单词就会执行一次插入操作,才会出现输入多个字符/单词时标签重复生成的问题。
修复方案
- 将标签插入逻辑移到循环外部,仅在用户输入内容不为空时执行一次
- 调整用户输入内容的初始y轴坐标,避免和上方标签重叠
- 输入内容清空时,标签会自动不渲染,符合你的需求
修改后的完整代码
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
相关产品推荐
相关产品推荐

