让我们在 Figma 中编辑一个文本块,如图所示:
segmentsFigma 插件 API为该文本块提供以下内容:
segments
const segments = [ { "characters": "Lorem ", "fontWeight": 400, "listOptions": { "type": "NONE" }, "indentation": 0, "hyperlink": null }, { "characters": "Ipsum", "fontWeight": 700, "listOptions": { "type": "NONE" }, "indentation": 0, "hyperlink": null }, { "characters": " is \nsimply dummy text of \n", "fontWeight": 400, "listOptions": { "type": "NONE" }, "indentation": 0, "hyperlink": null }, { "characters": "the printing and \n", "fontWeight": 400, "listOptions": { "type": "UNORDERED" }, "indentation": 1, "hyperlink": null }, { "characters": "typesetting \n", "fontWeight": 400, "listOptions": { "type": "UNORDERED" }, "indentation": 2, "hyperlink": null }, { "characters": "industry. \n", "fontWeight": 400, "listOptions": { "type": "UNORDERED" }, "indentation": 1, "hyperlink": null }, { "characters": "Lorem Ipsum has been the ", "fontWeight": 400, "listOptions": { "type": "NONE" }, "indentation": 0, "hyperlink": null }, { "characters": "industry's standard", "fontWeight": 400, "listOptions": { "type": "NONE" }, "indentation": 0, "hyperlink": { "type": "URL", "value": "http://example.com" } }, { "characters": " dummy text ever since the 1500s, \n", "fontWeight": 400, "listOptions": { "type": "NONE" }, "indentation": 0, "hyperlink": null }, { "characters": "when an unknown \n", "fontWeight": 400, "listOptions": { "type": "ORDERED" }, "indentation": 1, "hyperlink": null }, { "characters": "printer took \na galley of \ntype and \n", "fontWeight": 400, "listOptions": { "type": "UNORDERED" }, "indentation": 2, "hyperlink": null }, { "characters": "scrambled it\n", "fontWeight": 400, "listOptions": { "type": "ORDERED" }, "indentation": 1, "hyperlink": null }, { "characters": "\nto make a type\n\n", "fontWeight": 400, "listOptions": { "type": "NONE" }, "indentation": 0, "hyperlink": null }, { "characters": "specimen book.\n", "fontWeight": 400, "listOptions": { "type": "UNORDERED" }, "indentation": 1, "hyperlink": null }, { "characters": "It has survived\n", "fontWeight": 400, "listOptions": { "type": "ORDERED" }, "indentation": 3, "hyperlink": null }, { "characters": "not only\nfive centuries,", "fontWeight": 400, "listOptions": { "type": "ORDERED" }, "indentation": 2, "hyperlink": null } ]
由于列表很长,让我们稍微简化一下:
const segments = [ { ind: 0, list: null, chars: "Lorem ", bold: false, link: null }, { ind: 0, list: null, chars: "Ipsum", bold: true, link: null }, { ind: 0, list: null, chars: " is \nsimply dummy text of \n", bold: false, link: null }, { ind: 1, list: "UL", chars: "the printing and \n", bold: false, link: null }, { ind: 2, list: "UL", chars: "typesetting \n", bold: false, link: null }, { ind: 1, list: "UL", chars: "industry. \n", bold: false, link: null }, { ind: 0, list: null, chars: "Lorem Ipsum has been the ", bold: false, link: null }, { ind: 0, list: null, chars: "industry's standard", bold: false, link: "http://example.com" }, { ind: 0, list: null, chars: " dummy text ever since the 1500s, \n", bold: false, link: null }, { ind: 1, list: "OL", chars: "when an unknown \n", bold: false, link: null }, { ind: 2, list: "UL", chars: "printer took \na galley of \ntype and \n", bold: false, link: null }, { ind: 1, list: "OL", chars: "scrambled it\n", bold: false, link: null }, { ind: 0, list: null, chars: "\nto make a type\n\n", bold: false, link: null }, { ind: 1, list: "UL", chars: "specimen book.\n", bold: false, link: null }, { ind: 3, list: "OL", chars: "It has survived\n", bold: false, link: null }, { ind: 2, list: "OL", chars: " not only\nfive centuries,", bold: false, link: null } ]
我正在尝试获取此段数据并使用 Javascript 将其转换为 HTML 树。输出应如下所示:
<span>Lorem </span> <strong>Ipsum</strong> <span> is <br>simply dummy text of </span> <ul> <li> <span>the printing and </span> </li> <ul> <li><span>typesettting </span></li> </ul> <li><span>industry. </span></li> </ul> <span>Lorem Ipsum has been the </span> <a href="http://example.com">industry's standard</a> <span> dummy text ever since the 1500s, </span> <ol> <li><span>when an unknown </span></li> <ul> <li><span>printer took </span></li> <li><span>a galley of </span></li> <li><span>type and </span></li> </ul> <li><span>scrambled it</span></li> </ol> <span>to make a type</span> <ul> <li> <span>specimen book.</span> </li> <ol> <ol> <li><span>It has survived</span></li> </ol> <li><span>not only</span></li> <li><span>five countries,</span></li> </ol> </ul>
我试过:
function getPureSegment(chars: string) { if (chars.endsWith("\n")) chars = chars.slice(0, -1) return ["<span>", chars.replaceAll(/\n/g, "<br>"), "</span>"] } function getOpeningListTag(segment) { const type = segment.listOptions.type if (type === "ORDERED") return "<ol>" if (type === "UNORDERED") return "<ul>" } function getClosingListTag(segment) { const type = segment.listOptions.type if (type === "ORDERED") return "</ol>" if (type === "UNORDERED") return "</ul>" } function getHtml(segments) { let prevSegment = { indentation: 0 } return segments.flatMap((segment, idx) => { const pure = getPureSegment(segment.characters) let line const endsBreakLine = segment.characters.endsWith("\n") const isLastSegment = idx === segments.length - 1 if (segment.indentation == 0) { if (segment.indentation < prevSegment.indentation) { line = [getClosingListTag(prevSegment), ...pure] } else { line = pure } } else if (segment.indentation > 0) { if (segment.indentation > prevSegment.indentation) { line = [getOpeningListTag(segment), "<li>", ...pure, (isLastSegment || segments[idx + 1].indentation < segment.indentation) && "</li>"].filter(Boolean) } else if (segment.indentation == prevSegment.indentation) { line = [segments[idx - 1].characters.endsWith("\n") && "<li>", ...pure, endsBreakLine && "</li>"].filter(Boolean) } else { line = [getClosingListTag(segment), "<li>", ...pure, endsBreakLine && "</li>"].filter(Boolean) } if (isLastSegment) line.push("</ul>".repeat(segment.indentation)) } prevSegment = segment return line }).join("\n") }
您的代码看起来几乎正确,但是有一些地方需要调整。下面是我对您的函数的一些修改和补充:
function getHtml(segments) { let prevSegment = { indentation: 0 } let html = ""; segments.forEach((segment, idx) => { const pure = getPureSegment(segment.chars); let line = ""; const endsBreakLine = segment.chars.endsWith("\n"); const isLastSegment = idx === segments.length - 1; if (segment.ind === 0) { if (segment.ind < prevSegment.ind) { line = getClosingListTag(prevSegment) + pure.join(""); } else { line = pure.join(""); } } else if (segment.ind > 0) { if (segment.ind > prevSegment.ind) { line = getOpeningListTag(segment) + "<li>" + pure.join("") + (isLastSegment || segments[idx + 1].ind < segment.ind ? "</li>" : ""); } else if (segment.ind === prevSegment.ind) { line = (segments[idx - 1].chars.endsWith("\n") ? "<li>" : "") + pure.join("") + (endsBreakLine ? "</li>" : ""); } else { line = getClosingListTag(segment) + "<li>" + pure.join("") + (endsBreakLine ? "</li>" : ""); } if (isLastSegment) { for (let i = segment.ind; i > 0; i--) { line += "</ul>"; } } } prevSegment = segment; html += line + "\n"; }); return html; }
在这个修改后的函数中,我做了以下几个修改和调整:
getHtml
forEach
flatMap
segment.characters
segment.chars
pure
line
if-else
filter(Boolean)
html
我希望这些修改能够解决您的问题,并产生您期望的HTML输出。